Modernize and refactor the requirement checking code

Before we had FuInstallTask which represented the specific install
action (install foo on bar), FuEngineRequest which described why the
install task was created, and FuEngine. The latter being both reposible
for calling *into* FuInstallTask and also *from* FuInstallTask as well.

Depending on the code, we had XbNodes of component and release, *and*
FwupdReleases as releases and lots of duplicated code to marshall the
former into various forms of the latter.

Create a FuRelease wrapper around FwupdRelease to replace FuInstallTask
and to simplify the code. Make the FuRelease builder do the device
requirement checks, and then use the engine to do checks requiring
engine state and context.
This commit is contained in:
Richard Hughes 2022-03-25 09:41:22 +00:00
parent 16edfd345e
commit 0eeaad76ec
10 changed files with 1922 additions and 1625 deletions

File diff suppressed because it is too large Load Diff

View File

@ -15,9 +15,8 @@
#include "fu-common.h"
#include "fu-context.h"
#include "fu-engine-request.h"
#include "fu-install-task.h"
#include "fu-plugin.h"
#include "fu-release.h"
#include "fu-security-attrs.h"
#define FU_TYPE_ENGINE (fu_engine_get_type())
@ -160,13 +159,12 @@ fu_engine_composite_prepare(FuEngine *self, GPtrArray *devices, GError **error);
gboolean
fu_engine_composite_cleanup(FuEngine *self, GPtrArray *devices, GError **error);
gboolean
fu_engine_install(FuEngine *self,
FuInstallTask *task,
GBytes *blob_cab,
FuProgress *progress,
FwupdInstallFlags flags,
FwupdFeatureFlags feature_flags,
GError **error);
fu_engine_install_release(FuEngine *self,
FuRelease *task,
GBytes *blob_cab,
FuProgress *progress,
FwupdInstallFlags flags,
GError **error);
gboolean
fu_engine_install_blob(FuEngine *self,
FuDevice *device,
@ -176,13 +174,13 @@ fu_engine_install_blob(FuEngine *self,
FwupdFeatureFlags feature_flags,
GError **error);
gboolean
fu_engine_install_tasks(FuEngine *self,
FuEngineRequest *request,
GPtrArray *install_tasks,
GBytes *blob_cab,
FuProgress *progress,
FwupdInstallFlags flags,
GError **error);
fu_engine_install_releases(FuEngine *self,
FuEngineRequest *request,
GPtrArray *releases,
GBytes *blob_cab,
FuProgress *progress,
FwupdInstallFlags flags,
GError **error);
GPtrArray *
fu_engine_get_details(FuEngine *self, FuEngineRequest *request, gint fd, GError **error);
gboolean
@ -221,11 +219,10 @@ fu_engine_add_plugin(FuEngine *self, FuPlugin *plugin);
void
fu_engine_add_runtime_version(FuEngine *self, const gchar *component_id, const gchar *version);
gboolean
fu_engine_check_trust(FuEngine *self, FuInstallTask *task, GError **error);
fu_engine_check_trust(FuEngine *self, FuRelease *task, GError **error);
gboolean
fu_engine_check_requirements(FuEngine *self,
FuEngineRequest *request,
FuInstallTask *task,
FuRelease *release,
FwupdInstallFlags flags,
GError **error);
void

View File

@ -1,551 +0,0 @@
/*
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "FuInstallTask"
#include "config.h"
#include <fwupd.h>
#include "fu-common-version.h"
#include "fu-common.h"
#include "fu-device-private.h"
#include "fu-install-task.h"
#include "fu-keyring-utils.h"
struct _FuInstallTask {
GObject parent_instance;
FuDevice *device;
XbNode *component;
FwupdReleaseFlags trust_flags;
gboolean is_downgrade;
};
G_DEFINE_TYPE(FuInstallTask, fu_install_task, G_TYPE_OBJECT)
/**
* fu_install_task_get_device:
* @self: a #FuInstallTask
*
* Gets the device for this task.
*
* Returns: (transfer none): the device
**/
FuDevice *
fu_install_task_get_device(FuInstallTask *self)
{
g_return_val_if_fail(FU_IS_INSTALL_TASK(self), NULL);
return self->device;
}
/**
* fu_install_task_get_component:
* @self: a #FuInstallTask
*
* Gets the component for this task.
*
* Returns: (transfer none): the component
**/
XbNode *
fu_install_task_get_component(FuInstallTask *self)
{
g_return_val_if_fail(FU_IS_INSTALL_TASK(self), NULL);
return self->component;
}
/**
* fu_install_task_get_trust_flags:
* @self: a #FuInstallTask
*
* Gets the trust flags for this task.
*
* NOTE: This is only set after fu_install_task_check_requirements() has been
* called successfully.
*
* Returns: the #FwupdReleaseFlags, e.g. #FWUPD_TRUST_FLAG_PAYLOAD
**/
FwupdReleaseFlags
fu_install_task_get_trust_flags(FuInstallTask *self)
{
g_return_val_if_fail(FU_IS_INSTALL_TASK(self), FALSE);
return self->trust_flags;
}
/**
* fu_install_task_get_is_downgrade:
* @self: a #FuInstallTask
*
* Gets if this task is to downgrade firmware.
*
* NOTE: This is only set after fu_install_task_check_requirements() has been
* called successfully.
*
* Returns: %TRUE if versions numbers are going backwards
**/
gboolean
fu_install_task_get_is_downgrade(FuInstallTask *self)
{
g_return_val_if_fail(FU_IS_INSTALL_TASK(self), FALSE);
return self->is_downgrade;
}
static gchar *
fu_install_task_verfmts_to_string(GPtrArray *verfmts)
{
GString *str = g_string_new(NULL);
for (guint i = 0; i < verfmts->len; i++) {
XbNode *verfmt = g_ptr_array_index(verfmts, i);
const gchar *tmp = xb_node_get_text(verfmt);
g_string_append_printf(str, "%s;", tmp);
}
if (str->len > 0)
g_string_truncate(str, str->len - 1);
return g_string_free(str, FALSE);
}
static gboolean
fu_install_task_check_verfmt(FuInstallTask *self,
GPtrArray *verfmts,
FwupdInstallFlags flags,
GError **error)
{
FwupdVersionFormat fmt_dev = fu_device_get_version_format(self->device);
g_autofree gchar *verfmts_str = NULL;
/* no device format */
if (fmt_dev == FWUPD_VERSION_FORMAT_UNKNOWN && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
verfmts_str = fu_install_task_verfmts_to_string(verfmts);
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"release version format '%s' but no device version format",
verfmts_str);
return FALSE;
}
/* compare all version formats */
for (guint i = 0; i < verfmts->len; i++) {
XbNode *verfmt = g_ptr_array_index(verfmts, i);
const gchar *tmp = xb_node_get_text(verfmt);
FwupdVersionFormat fmt_rel = fwupd_version_format_from_string(tmp);
if (fmt_dev == fmt_rel)
return TRUE;
}
verfmts_str = fu_install_task_verfmts_to_string(verfmts);
if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Firmware version formats were different, "
"device was '%s' and release is '%s'",
fwupd_version_format_to_string(fmt_dev),
verfmts_str);
return FALSE;
}
g_warning("ignoring version format difference %s:%s",
fwupd_version_format_to_string(fmt_dev),
verfmts_str);
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
* @flags: install flags, e.g. #FWUPD_INSTALL_FLAG_ALLOW_OLDER
* @error: (nullable): optional return location for an error
*
* Checks any requirements of this task. This will typically involve checking
* that the device can accept the component (the GUIDs match) and that the
* device can be upgraded with this firmware version.
*
* Returns: %TRUE if the requirements passed
**/
gboolean
fu_install_task_check_requirements(FuInstallTask *self, FwupdInstallFlags flags, GError **error)
{
const gchar *branch_new;
const gchar *branch_old;
const gchar *protocol;
const gchar *version;
const gchar *version_release_raw;
const gchar *version_lowest;
gboolean matches_guid = FALSE;
gint vercmp;
g_autofree gchar *version_release = NULL;
g_autoptr(GError) error_local = NULL;
g_autoptr(GPtrArray) provides = NULL;
g_autoptr(GPtrArray) verfmts = NULL;
g_autoptr(XbNode) release = NULL;
#if LIBXMLB_CHECK_VERSION(0, 2, 0)
g_autoptr(XbQuery) query = NULL;
#endif
g_return_val_if_fail(FU_IS_INSTALL_TASK(self), FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* does this component provide a GUID the device has */
provides =
xb_node_query(self->component, "provides/firmware[@type='flashed']", 0, &error_local);
if (provides == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"No supported devices found: %s",
error_local->message);
return FALSE;
}
for (guint i = 0; i < provides->len; i++) {
XbNode *provide = g_ptr_array_index(provides, i);
if (fu_device_has_guid(self->device, xb_node_get_text(provide))) {
matches_guid = TRUE;
break;
}
}
if (!matches_guid) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"No supported devices found");
return FALSE;
}
/* device requires 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']", NULL);
if (fu_device_get_protocols(self->device)->len != 0 && protocol != NULL &&
!fu_device_has_protocol(self->device, protocol) &&
(flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
g_autofree gchar *str = NULL;
str = fu_common_strjoin_array("|", fu_device_get_protocols(self->device));
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Device %s does not support %s, only %s",
fu_device_get_name(self->device),
protocol,
str);
return FALSE;
}
/* check the device is not locked */
if (fu_device_has_flag(self->device, FWUPD_DEVICE_FLAG_LOCKED)) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Device %s [%s] is locked",
fu_device_get_name(self->device),
fu_device_get_id(self->device));
return FALSE;
}
/* check the branch is not switching */
branch_new = xb_node_query_text(self->component, "branch", NULL);
branch_old = fu_device_get_branch(self->device);
if ((flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) == 0 &&
g_strcmp0(branch_old, branch_new) != 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Device %s [%s] would switch firmware branch from %s to %s",
fu_device_get_name(self->device),
fu_device_get_id(self->device),
branch_old != NULL ? branch_old : "default",
branch_new != NULL ? branch_new : "default");
return FALSE;
}
/* no update abilities */
if (!fu_device_has_flag(self->device, FWUPD_DEVICE_FLAG_UPDATABLE)) {
g_autoptr(GString) str = g_string_new(NULL);
g_string_append_printf(str,
"Device %s [%s] does not currently allow updates",
fu_device_get_name(self->device),
fu_device_get_id(self->device));
if (fu_device_get_update_error(self->device) != NULL) {
g_string_append_printf(str,
": %s",
fu_device_get_update_error(self->device));
}
g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, str->str);
return FALSE;
}
/* called with online update, test if device is supposed to allow this */
if ((flags & FWUPD_INSTALL_FLAG_OFFLINE) == 0 && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0 &&
fu_device_has_flag(self->device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Device %s [%s] only allows offline updates",
fu_device_get_name(self->device),
fu_device_get_id(self->device));
return FALSE;
}
/* get device */
version = fu_device_get_version(self->device);
if (version == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Device %s [%s] has no firmware version",
fu_device_get_name(self->device),
fu_device_get_id(self->device));
return FALSE;
}
/* get latest release */
#if LIBXMLB_CHECK_VERSION(0, 2, 0)
query = xb_query_new_full(xb_node_get_silo(self->component),
"releases/release",
XB_QUERY_FLAG_FORCE_NODE_CACHE,
error);
if (query == NULL)
return FALSE;
release = xb_node_query_first_full(self->component, query, NULL);
#else
release = xb_node_query_first(self->component, "releases/release", NULL);
#endif
if (release == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"%s [%s] has no firmware update metadata",
fu_device_get_name(self->device),
fu_device_get_id(self->device));
return FALSE;
}
/* is this a downgrade or re-install */
version_release_raw = xb_node_get_attr(release, "version");
if (version_release_raw == NULL) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"Release has no firmware version");
return FALSE;
}
/* check the version formats match if set in the release */
if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 &&
(flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) == 0) {
verfmts = xb_node_query(self->component,
"custom/value[@key='LVFS::VersionFormat']",
0,
NULL);
if (verfmts != NULL) {
if (!fu_install_task_check_verfmt(self, verfmts, flags, error))
return FALSE;
}
}
/* compare to the lowest supported version, if it exists */
version_lowest = fu_device_get_version_lowest(self->device);
if (version_lowest != NULL &&
fu_common_vercmp_full(version_lowest,
version,
fu_device_get_version_format(self->device)) > 0 &&
(flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_VERSION_NEWER,
"Specified firmware is older than the minimum "
"required version '%s < %s'",
version,
version_lowest);
return FALSE;
}
/* check semver */
if (fu_device_get_version_format(self->device) == FWUPD_VERSION_FORMAT_PLAIN) {
version_release = g_strdup(version_release_raw);
} else {
version_release =
fu_common_version_parse_from_format(version_release_raw,
fu_device_get_version_format(self->device));
}
vercmp = fu_common_vercmp_full(version,
version_release,
fu_device_get_version_format(self->device));
if (fu_device_has_flag(self->device, FWUPD_DEVICE_FLAG_ONLY_VERSION_UPGRADE) &&
vercmp >= 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Device only supports version upgrades");
return FALSE;
}
if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_VERSION_SAME,
"Specified firmware is already installed '%s'",
version_release);
return FALSE;
}
self->is_downgrade = vercmp > 0;
if (self->is_downgrade && (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0 &&
(flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) == 0) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_VERSION_NEWER,
"Specified firmware is older than installed '%s < %s'",
version_release,
version);
return FALSE;
}
/* verify */
if (!fu_keyring_get_release_flags(release, &self->trust_flags, &error_local)) {
if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
g_warning("Ignoring verification for %s: %s",
fu_device_get_name(self->device),
error_local->message);
} else {
g_propagate_error(error, g_steal_pointer(&error_local));
return FALSE;
}
}
return TRUE;
}
/**
* fu_install_task_get_action_id:
* @self: a #FuEngine
*
* Gets the PolicyKit action ID to use for the install operation.
*
* Returns: string, e.g. `org.freedesktop.fwupd.update-internal-trusted`
**/
const gchar *
fu_install_task_get_action_id(FuInstallTask *self)
{
/* relax authentication checks for removable devices */
if (!fu_device_has_flag(self->device, FWUPD_DEVICE_FLAG_INTERNAL)) {
if (self->is_downgrade) {
if (self->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD)
return "org.freedesktop.fwupd.downgrade-hotplug-trusted";
return "org.freedesktop.fwupd.downgrade-hotplug";
}
if (self->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD)
return "org.freedesktop.fwupd.update-hotplug-trusted";
return "org.freedesktop.fwupd.update-hotplug";
}
/* internal device */
if (self->is_downgrade) {
if (self->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD)
return "org.freedesktop.fwupd.downgrade-internal-trusted";
return "org.freedesktop.fwupd.downgrade-internal";
}
if (self->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD)
return "org.freedesktop.fwupd.update-internal-trusted";
return "org.freedesktop.fwupd.update-internal";
}
static void
fu_install_task_init(FuInstallTask *self)
{
self->trust_flags = FWUPD_TRUST_FLAG_NONE;
}
static void
fu_install_task_finalize(GObject *object)
{
FuInstallTask *self = FU_INSTALL_TASK(object);
if (self->component != NULL)
g_object_unref(self->component);
if (self->device != NULL)
g_object_unref(self->device);
G_OBJECT_CLASS(fu_install_task_parent_class)->finalize(object);
}
static void
fu_install_task_class_init(FuInstallTaskClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = fu_install_task_finalize;
}
/**
* fu_install_task_compare:
* @task1: first task to compare.
* @task2: second task to compare.
*
* Compares two install tasks.
*
* Returns: 1, 0 or -1 if @task1 is greater, equal, or less than @task2, respectively.
**/
gint
fu_install_task_compare(FuInstallTask *task1, FuInstallTask *task2)
{
FuDevice *device1 = fu_install_task_get_device(task1);
FuDevice *device2 = fu_install_task_get_device(task2);
if (fu_device_get_order(device1) < fu_device_get_order(device2))
return -1;
if (fu_device_get_order(device1) > fu_device_get_order(device2))
return 1;
return 0;
}
/**
* fu_install_task_new:
* @device: a device
* @component: a Xmlb node
*
* Creates a new install task that may or may not be valid.
*
* Returns: (transfer full): the #FuInstallTask
**/
FuInstallTask *
fu_install_task_new(FuDevice *device, XbNode *component)
{
FuInstallTask *self;
self = g_object_new(FU_TYPE_TASK, NULL);
if (component != NULL)
self->component = g_object_ref(component);
if (device != NULL)
self->device = g_object_ref(device);
return FU_INSTALL_TASK(self);
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <glib-object.h>
#include <xmlb.h>
#include "fu-device.h"
#define FU_TYPE_TASK (fu_install_task_get_type())
G_DECLARE_FINAL_TYPE(FuInstallTask, fu_install_task, FU, INSTALL_TASK, GObject)
FuInstallTask *
fu_install_task_new(FuDevice *device, XbNode *component);
FuDevice *
fu_install_task_get_device(FuInstallTask *self);
XbNode *
fu_install_task_get_component(FuInstallTask *self);
FwupdReleaseFlags
fu_install_task_get_trust_flags(FuInstallTask *self);
gboolean
fu_install_task_get_is_downgrade(FuInstallTask *self);
gboolean
fu_install_task_check_requirements(FuInstallTask *self, FwupdInstallFlags flags, GError **error);
const gchar *
fu_install_task_get_action_id(FuInstallTask *self);
gint
fu_install_task_compare(FuInstallTask *task1, FuInstallTask *task2);

View File

@ -40,7 +40,7 @@
#include "fu-debug.h"
#include "fu-device-private.h"
#include "fu-engine.h"
#include "fu-install-task.h"
#include "fu-release.h"
#include "fu-security-attrs-private.h"
#ifdef HAVE_POLKIT
@ -364,9 +364,10 @@ typedef struct {
#ifdef HAVE_POLKIT
PolkitSubject *subject;
#endif
GPtrArray *install_tasks;
GPtrArray *releases;
GPtrArray *action_ids;
GPtrArray *checksums;
GPtrArray *errors;
guint64 flags;
GBytes *blob_cab;
FuMainPrivate *priv;
@ -390,12 +391,14 @@ fu_main_auth_helper_free(FuMainAuthHelper *helper)
g_object_unref(helper->silo);
if (helper->request != NULL)
g_object_unref(helper->request);
if (helper->install_tasks != NULL)
g_ptr_array_unref(helper->install_tasks);
if (helper->releases != NULL)
g_ptr_array_unref(helper->releases);
if (helper->action_ids != NULL)
g_ptr_array_unref(helper->action_ids);
if (helper->checksums != NULL)
g_ptr_array_unref(helper->checksums);
if (helper->errors != NULL)
g_ptr_array_unref(helper->errors);
g_free(helper->device_id);
g_free(helper->remote_id);
g_free(helper->key);
@ -807,13 +810,13 @@ fu_main_authorize_install_queue(FuMainAuthHelper *helper_ref)
/* all authenticated, so install all the things */
priv->update_in_progress = TRUE;
ret = fu_engine_install_tasks(helper->priv->engine,
helper->request,
helper->install_tasks,
helper->blob_cab,
progress,
helper->flags,
&error);
ret = fu_engine_install_releases(helper->priv->engine,
helper->request,
helper->releases,
helper->blob_cab,
progress,
helper->flags,
&error);
priv->update_in_progress = FALSE;
if (priv->pending_sigterm)
g_main_loop_quit(priv->loop);
@ -845,11 +848,126 @@ g_ptr_array_find(GPtrArray *haystack, gconstpointer needle, guint *index_)
#endif
static gint
fu_main_install_task_sort_cb(gconstpointer a, gconstpointer b)
fu_main_release_sort_cb(gconstpointer a, gconstpointer b)
{
FuInstallTask *task_a = *((FuInstallTask **)a);
FuInstallTask *task_b = *((FuInstallTask **)b);
return fu_install_task_compare(task_a, task_b);
FuRelease *release1 = *((FuRelease **)a);
FuRelease *release2 = *((FuRelease **)b);
return fu_release_compare(release1, release2);
}
static gboolean
fu_main_install_with_helper_device(FuMainAuthHelper *helper,
XbNode *component,
FuDevice *device,
GError **error)
{
FuMainPrivate *priv = helper->priv;
const gchar *action_id;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error_local = NULL;
g_autoptr(GPtrArray) releases = NULL;
/* is this component valid for the device */
fu_release_set_device(release, device);
fu_release_set_request(release, helper->request);
if (!fu_release_load(release,
component,
NULL,
helper->flags | FWUPD_INSTALL_FLAG_FORCE,
&error_local)) {
g_ptr_array_add(helper->errors, g_steal_pointer(&error_local));
return TRUE;
}
if (!fu_engine_check_requirements(priv->engine,
release,
helper->flags | FWUPD_INSTALL_FLAG_FORCE,
&error_local)) {
if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) {
g_debug("first pass requirement on %s:%s failed: %s",
fu_device_get_id(device),
xb_node_query_text(component, "id", NULL),
error_local->message);
}
g_ptr_array_add(helper->errors, g_steal_pointer(&error_local));
return TRUE;
}
/* possibly update version format */
fu_engine_md_refresh_device_from_component(priv->engine, device, component);
/* sync update message from CAB */
fu_device_incorporate_from_component(device, component);
/* install each intermediate release */
releases = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES)) {
g_autoptr(GPtrArray) rels = NULL;
#if LIBXMLB_CHECK_VERSION(0, 2, 0)
g_autoptr(XbQuery) query = NULL;
#endif
/* we get this one "for free" */
g_ptr_array_add(releases, g_object_ref(release));
#if LIBXMLB_CHECK_VERSION(0, 2, 0)
query = xb_query_new_full(xb_node_get_silo(component),
"releases/release",
XB_QUERY_FLAG_FORCE_NODE_CACHE,
error);
if (query == NULL)
return FALSE;
rels = xb_node_query_full(component, query, NULL);
#else
rels = xb_node_query(component, "releases/release", 0, NULL);
#endif
/* add all but the the first entry */
for (guint i = 1; i < rels->len; i++) {
XbNode *rel = g_ptr_array_index(rels, i);
g_autoptr(FuRelease) release2 = fu_release_new();
g_autoptr(GError) error_loop = NULL;
fu_release_set_device(release2, device);
fu_release_set_request(release2, helper->request);
if (!fu_release_load(release2,
component,
rel,
helper->flags,
&error_loop)) {
g_ptr_array_add(helper->errors, g_steal_pointer(&error_loop));
continue;
}
g_ptr_array_add(releases, g_object_ref(release2));
}
} else {
g_ptr_array_add(releases, g_object_ref(release));
}
/* make a second pass */
for (guint i = 0; i < releases->len; i++) {
FuRelease *release_tmp = g_ptr_array_index(releases, i);
if (!fu_engine_check_requirements(priv->engine,
release_tmp,
helper->flags,
&error_local)) {
g_debug("second pass requirement on %s:%s failed: %s",
fu_device_get_id(device),
xb_node_query_text(component, "id", NULL),
error_local->message);
g_ptr_array_add(helper->errors, g_steal_pointer(&error_local));
continue;
}
if (!fu_engine_check_trust(priv->engine, release_tmp, &error_local)) {
g_ptr_array_add(helper->errors, g_steal_pointer(&error_local));
continue;
}
/* get the action IDs for the valid device */
action_id = fu_release_get_action_id(release_tmp);
if (!g_ptr_array_find(helper->action_ids, action_id, NULL))
g_ptr_array_add(helper->action_ids, g_strdup(action_id));
g_ptr_array_add(helper->releases, g_object_ref(release_tmp));
}
/* success */
return TRUE;
}
static gboolean
@ -859,7 +977,6 @@ fu_main_install_with_helper(FuMainAuthHelper *helper_ref, GError **error)
g_autoptr(FuMainAuthHelper) helper = helper_ref;
g_autoptr(GPtrArray) components = NULL;
g_autoptr(GPtrArray) devices_possible = NULL;
g_autoptr(GPtrArray) errors = NULL;
/* get a list of devices that in some way match the device_id */
if (g_strcmp0(helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
@ -890,73 +1007,25 @@ fu_main_install_with_helper(FuMainAuthHelper *helper_ref, GError **error)
if (components == NULL)
return FALSE;
helper->action_ids = g_ptr_array_new_with_free_func(g_free);
helper->install_tasks = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
errors = g_ptr_array_new_with_free_func((GDestroyNotify)g_error_free);
helper->releases = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
helper->errors = g_ptr_array_new_with_free_func((GDestroyNotify)g_error_free);
/* do any devices pass the requirements */
for (guint i = 0; i < components->len; i++) {
XbNode *component = g_ptr_array_index(components, i);
/* do any devices pass the requirements */
for (guint j = 0; j < devices_possible->len; j++) {
FuDevice *device = g_ptr_array_index(devices_possible, j);
const gchar *action_id;
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(GError) error_local = NULL;
/* is this component valid for the device */
task = fu_install_task_new(device, component);
if (!fu_engine_check_requirements(priv->engine,
helper->request,
task,
helper->flags | FWUPD_INSTALL_FLAG_FORCE,
&error_local)) {
if (!g_error_matches(error_local,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND)) {
g_debug("first pass requirement on %s:%s failed: %s",
fu_device_get_id(device),
xb_node_query_text(component, "id", NULL),
error_local->message);
}
g_ptr_array_add(errors, g_steal_pointer(&error_local));
continue;
}
/* make a second pass using possibly updated version format now */
fu_engine_md_refresh_device_from_component(priv->engine, device, component);
if (!fu_engine_check_requirements(priv->engine,
helper->request,
task,
helper->flags,
&error_local)) {
g_debug("second pass requirement on %s:%s failed: %s",
fu_device_get_id(device),
xb_node_query_text(component, "id", NULL),
error_local->message);
g_ptr_array_add(errors, g_steal_pointer(&error_local));
continue;
}
if (!fu_engine_check_trust(priv->engine, task, &error_local)) {
g_ptr_array_add(errors, g_steal_pointer(&error_local));
continue;
}
/* if component should have an update message from CAB */
fu_device_incorporate_from_component(device, component);
/* get the action IDs for the valid device */
action_id = fu_install_task_get_action_id(task);
if (!g_ptr_array_find(helper->action_ids, action_id, NULL))
g_ptr_array_add(helper->action_ids, g_strdup(action_id));
g_ptr_array_add(helper->install_tasks, g_steal_pointer(&task));
if (!fu_main_install_with_helper_device(helper, component, device, error))
return FALSE;
}
}
/* order the install tasks by the device priority */
g_ptr_array_sort(helper->install_tasks, fu_main_install_task_sort_cb);
g_ptr_array_sort(helper->releases, fu_main_release_sort_cb);
/* nothing suitable */
if (helper->install_tasks->len == 0) {
GError *error_tmp = fu_common_error_array_get_best(errors);
if (helper->releases->len == 0) {
GError *error_tmp = fu_common_error_array_get_best(helper->errors);
g_propagate_error(error, error_tmp);
return FALSE;
}

1067
src/fu-release.c Normal file

File diff suppressed because it is too large Load Diff

64
src/fu-release.h Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <fwupd.h>
#include <xmlb.h>
#include "fu-config.h"
#include "fu-device.h"
#include "fu-engine-request.h"
#define FU_TYPE_RELEASE (fu_release_get_type())
G_DECLARE_FINAL_TYPE(FuRelease, fu_release, FU, RELEASE, FwupdRelease)
FuRelease *
fu_release_new(void);
#define fu_release_get_version(r) fwupd_release_get_version(FWUPD_RELEASE(r))
#define fu_release_get_branch(r) fwupd_release_get_branch(FWUPD_RELEASE(r))
#define fu_release_get_checksums(r) fwupd_release_get_checksums(FWUPD_RELEASE(r))
#define fu_release_add_flag(r, v) fwupd_release_add_flag(FWUPD_RELEASE(r), v)
#define fu_release_add_tag(r, v) fwupd_release_add_tag(FWUPD_RELEASE(r), v)
#define fu_release_add_metadata(r, v) fwupd_release_add_metadata(FWUPD_RELEASE(r), v)
FuDevice *
fu_release_get_device(FuRelease *self);
GBytes *
fu_release_get_fw_blob(FuRelease *self);
FuEngineRequest *
fu_release_get_request(FuRelease *self);
const gchar *
fu_release_get_builder_script(FuRelease *self);
const gchar *
fu_release_get_builder_output(FuRelease *self);
GPtrArray *
fu_release_get_soft_reqs(FuRelease *self);
GPtrArray *
fu_release_get_hard_reqs(FuRelease *self);
void
fu_release_set_request(FuRelease *self, FuEngineRequest *request);
void
fu_release_set_device(FuRelease *self, FuDevice *device);
void
fu_release_set_remote(FuRelease *self, FwupdRemote *remote);
void
fu_release_set_config(FuRelease *self, FuConfig *config);
gboolean
fu_release_load(FuRelease *self,
XbNode *component,
XbNode *rel,
FwupdInstallFlags flags,
GError **error);
FwupdReleaseFlags
fu_release_get_trust_flags(FuRelease *self);
const gchar *
fu_release_get_action_id(FuRelease *self);
gint
fu_release_compare(FuRelease *release1, FuRelease *release2);

View File

@ -24,7 +24,6 @@
#include "fu-engine.h"
#include "fu-hash.h"
#include "fu-history.h"
#include "fu-install-task.h"
#include "fu-plugin-list.h"
#include "fu-plugin-private.h"
#include "fu-progressbar.h"
@ -206,12 +205,15 @@ fu_engine_requirements_missing_func(gconstpointer user_data)
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
const gchar *xml = "<component>"
" <requires>"
" <id compare=\"ge\" version=\"1.2.3\">not.going.to.exist</id>"
" </requires>"
" <releases>"
" <release version=\"1.2.3\"/>"
" </releases>"
"</component>";
/* set up a dummy version */
@ -226,8 +228,11 @@ fu_engine_requirements_missing_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task = fu_install_task_new(NULL, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert_false(ret);
}
@ -240,12 +245,15 @@ fu_engine_requirements_soft_func(gconstpointer user_data)
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
const gchar *xml = "<component>"
" <suggests>"
" <id compare=\"ge\" version=\"1.2.3\">not.going.to.exist</id>"
" </suggests>"
" <releases>"
" <release version=\"1.2.3\"/>"
" </releases>"
"</component>";
/* set up a dummy version */
@ -260,8 +268,11 @@ fu_engine_requirements_soft_func(gconstpointer user_data)
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);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_FORCE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -274,12 +285,15 @@ fu_engine_requirements_client_fail_func(gconstpointer user_data)
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
const gchar *xml = "<component>"
" <requires>"
" <client>detach-action</client>"
" </requires>"
" <releases>"
" <release version=\"1.2.3\"/>"
" </releases>"
"</component>";
/* make the component require one thing */
@ -291,8 +305,11 @@ fu_engine_requirements_client_fail_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task = fu_install_task_new(NULL, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_false(ret);
}
@ -305,12 +322,15 @@ fu_engine_requirements_client_invalid_func(gconstpointer user_data)
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
const gchar *xml = "<component>"
" <requires>"
" <client>hello-dave</client>"
" </requires>"
" <releases>"
" <release version=\"1.2.3\"/>"
" </releases>"
"</component>";
/* make the component require one thing */
@ -322,8 +342,11 @@ fu_engine_requirements_client_invalid_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task = fu_install_task_new(NULL, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert_false(ret);
}
@ -336,12 +359,15 @@ fu_engine_requirements_client_pass_func(gconstpointer user_data)
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
const gchar *xml = "<component>"
" <requires>"
" <client>detach-action</client>"
" </requires>"
" <releases>"
" <release version=\"1.2.3\"/>"
" </releases>"
"</component>";
/* set up a dummy version */
@ -356,8 +382,11 @@ fu_engine_requirements_client_pass_func(gconstpointer user_data)
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_NONE, &error);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -368,9 +397,8 @@ fu_engine_requirements_version_require_func(gconstpointer user_data)
FuTest *self = (FuTest *)user_data;
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -404,14 +432,64 @@ fu_engine_requirements_version_require_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_true(
g_str_has_prefix(error->message, "device requires firmware with a version check"));
g_assert_false(ret);
}
static void
fu_engine_requirements_version_lowest_func(gconstpointer user_data)
{
FuTest *self = (FuTest *)user_data;
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
const gchar *xml =
"<component>"
" <provides>"
" <firmware type=\"flashed\">12345678-1234-1234-1234-123456789012</firmware>"
" </provides>"
" <releases>"
" <release version=\"1.2.2\">"
" </release>"
" </releases>"
"</component>";
/* set up a dummy device */
fu_device_set_version_format(device, FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_version(device, "1.2.3");
fu_device_set_version_lowest(device, "1.2.3");
fu_device_add_vendor_id(device, "FFFF");
fu_device_add_flag(device, FWUPD_DEVICE_FLAG_UPDATABLE);
fu_device_add_flag(device, FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD);
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 */
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_true(
g_str_has_prefix(error->message, "Specified firmware is older than the minimum"));
g_assert_false(ret);
}
static void
fu_engine_requirements_unsupported_func(gconstpointer user_data)
{
@ -420,12 +498,15 @@ fu_engine_requirements_unsupported_func(gconstpointer user_data)
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
const gchar *xml = "<component>"
" <requires>"
" <UNKNOWN compare=\"ge\" version=\"2.6.0\"/>"
" </requires>"
" <releases>"
" <release version=\"1.2.3\"/>"
" </releases>"
"</component>";
/* set up a dummy version */
@ -440,8 +521,11 @@ fu_engine_requirements_unsupported_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task = fu_install_task_new(NULL, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_false(ret);
}
@ -455,7 +539,7 @@ fu_engine_requirements_child_func(gconstpointer user_data)
g_autoptr(FuDevice) child = fu_device_new();
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -496,8 +580,12 @@ fu_engine_requirements_child_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this passes */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -511,7 +599,7 @@ fu_engine_requirements_child_fail_func(gconstpointer user_data)
g_autoptr(FuDevice) child = fu_device_new();
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -552,8 +640,12 @@ fu_engine_requirements_child_fail_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this passes */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_nonnull(
g_strstr_len(error->message, -1, "Not compatible with child device version"));
@ -565,7 +657,7 @@ fu_engine_requirements_func(gconstpointer user_data)
{
gboolean ret;
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
@ -574,6 +666,9 @@ fu_engine_requirements_func(gconstpointer user_data)
" <requires>"
" <id compare=\"ge\" version=\"1.2.3\">org.test.dummy</id>"
" </requires>"
" <releases>"
" <release version=\"1.2.3\"/>"
" </releases>"
"</component>";
/* set up some dummy versions */
@ -589,8 +684,11 @@ fu_engine_requirements_func(gconstpointer user_data)
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_NONE, &error);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -603,7 +701,7 @@ fu_engine_requirements_device_func(gconstpointer user_data)
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -647,8 +745,12 @@ fu_engine_requirements_device_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this passes */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -661,7 +763,7 @@ fu_engine_requirements_device_plain_func(gconstpointer user_data)
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -694,8 +796,12 @@ fu_engine_requirements_device_plain_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this passes */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -706,9 +812,8 @@ fu_engine_requirements_version_format_func(gconstpointer user_data)
FuTest *self = (FuTest *)user_data;
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -743,8 +848,9 @@ fu_engine_requirements_version_format_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_nonnull(
g_strstr_len(error->message, -1, "Firmware version formats were different"));
@ -757,9 +863,8 @@ fu_engine_requirements_only_upgrade_func(gconstpointer user_data)
FuTest *self = (FuTest *)user_data;
gboolean ret;
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -789,12 +894,9 @@ fu_engine_requirements_only_upgrade_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine,
request,
task,
FWUPD_INSTALL_FLAG_ALLOW_OLDER,
&error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_nonnull(g_strstr_len(error->message, -1, "Device only supports version upgrades"));
g_assert_false(ret);
@ -811,8 +913,8 @@ fu_engine_requirements_sibling_device_func(gconstpointer user_data)
g_autoptr(FuDevice) parent = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task1 = NULL;
g_autoptr(FuInstallTask) task2 = NULL;
g_autoptr(FuRelease) release1 = fu_release_new();
g_autoptr(FuRelease) release2 = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -879,8 +981,12 @@ fu_engine_requirements_sibling_device_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task1 = fu_install_task_new(device1, component);
ret = fu_engine_check_requirements(engine, request, task1, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release1, device1);
fu_release_set_request(release1, request);
ret = fu_release_load(release1, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release1, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_false(ret);
g_clear_error(&error);
@ -900,8 +1006,12 @@ fu_engine_requirements_sibling_device_func(gconstpointer user_data)
fu_engine_add_device(engine, device2);
/* check this passes */
task2 = fu_install_task_new(device1, component);
ret = fu_engine_check_requirements(engine, request, task2, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release2, device1);
fu_release_set_request(release2, request);
ret = fu_release_load(release2, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release2, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -915,7 +1025,7 @@ fu_engine_requirements_other_device_func(gconstpointer user_data)
g_autoptr(FuDevice) device2 = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -966,8 +1076,12 @@ fu_engine_requirements_other_device_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this passes */
task = fu_install_task_new(device1, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device1);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -981,8 +1095,8 @@ fu_engine_requirements_protocol_check_func(gconstpointer user_data)
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(FuInstallTask) task1 = NULL;
g_autoptr(FuInstallTask) task2 = NULL;
g_autoptr(FuRelease) release1 = fu_release_new();
g_autoptr(FuRelease) release2 = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -1045,16 +1159,17 @@ fu_engine_requirements_protocol_check_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this fails */
task1 = fu_install_task_new(device1, component);
ret = fu_engine_check_requirements(engine, request, task1, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release1, device1);
fu_release_set_request(release1, request);
ret = fu_release_load(release1, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_false(ret);
g_clear_error(&error);
/* check this passes */
task2 = fu_install_task_new(device2, component);
ret = fu_engine_check_requirements(engine, request, task2, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release2, device2);
fu_release_set_request(release2, request);
ret = fu_release_load(release2, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -1068,7 +1183,7 @@ fu_engine_requirements_parent_device_func(gconstpointer user_data)
g_autoptr(FuDevice) device2 = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo = NULL;
@ -1121,8 +1236,12 @@ fu_engine_requirements_parent_device_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check this passes */
task = fu_install_task_new(device2, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device2);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
}
@ -1372,7 +1491,7 @@ fu_engine_require_hwid_func(gconstpointer user_data)
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
@ -1423,8 +1542,12 @@ fu_engine_require_hwid_func(gconstpointer user_data)
g_assert_nonnull(component);
/* check requirements */
task = fu_install_task_new(device, component);
ret = fu_engine_check_requirements(engine, request, task, FWUPD_INSTALL_FLAG_NONE, &error);
fu_release_set_device(release, device);
fu_release_set_request(release, request);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_check_requirements(engine, release, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE);
g_assert_nonnull(error);
g_assert_cmpstr(error->message,
@ -1717,7 +1840,7 @@ fu_engine_history_func(gconstpointer user_data)
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuHistory) history = NULL;
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
g_autoptr(FwupdDevice) device3 = NULL;
g_autoptr(FwupdDevice) device4 = NULL;
@ -1784,14 +1907,16 @@ fu_engine_history_func(gconstpointer user_data)
fu_device_set_metadata_integer(device, "nr-update", 0);
/* install it */
task = fu_install_task_new(device, component);
ret = fu_engine_install(engine,
task,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
FWUPD_FEATURE_FLAG_NONE,
&error);
fu_release_set_device(release, device);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_install_release(engine,
release,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error(error);
g_assert_true(ret);
@ -1860,13 +1985,18 @@ fu_engine_multiple_rels_func(gconstpointer user_data)
g_autofree gchar *filename = NULL;
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(XbNode) component = NULL;
g_autoptr(XbSilo) silo_empty = xb_silo_new();
g_autoptr(XbSilo) silo = NULL;
g_autoptr(FuEngineRequest) request = fu_engine_request_new(FU_ENGINE_REQUEST_KIND_ACTIVE);
g_autoptr(GPtrArray) releases = NULL;
g_autoptr(GPtrArray) rels = NULL;
#if LIBXMLB_CHECK_VERSION(0, 2, 0)
g_autoptr(XbQuery) query = NULL;
#endif
/* ensure empty tree */
fu_self_test_mkroot();
@ -1921,15 +2051,40 @@ fu_engine_multiple_rels_func(gconstpointer user_data)
/* set up counter */
fu_device_set_metadata_integer(device, "nr-update", 0);
/* install it */
task = fu_install_task_new(device, component);
ret = fu_engine_install(engine,
task,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
FWUPD_FEATURE_FLAG_NONE,
&error);
/* get all */
#if LIBXMLB_CHECK_VERSION(0, 2, 0)
query = xb_query_new_full(xb_node_get_silo(component),
"releases/release",
XB_QUERY_FLAG_FORCE_NODE_CACHE,
&error);
g_assert_no_error(error);
g_assert_nonnull(query);
rels = xb_node_query_full(component, query, &error);
#else
rels = xb_node_query(component, "releases/release", 0, &error);
#endif
g_assert_no_error(error);
g_assert_nonnull(rels);
releases = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
for (guint i = 0; i < rels->len; i++) {
XbNode *rel = g_ptr_array_index(rels, i);
g_autoptr(FuRelease) release = fu_release_new();
fu_release_set_device(release, device);
ret = fu_release_load(release, component, rel, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
g_ptr_array_add(releases, g_object_ref(release));
}
/* install them */
ret = fu_engine_install_releases(engine,
request,
releases,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error(error);
g_assert_true(ret);
@ -1948,7 +2103,7 @@ fu_engine_history_inherit(gconstpointer user_data)
g_autofree gchar *history_db = NULL;
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error = NULL;
@ -2016,14 +2171,16 @@ fu_engine_history_inherit(gconstpointer user_data)
/* install it */
g_setenv("FWUPD_PLUGIN_TEST", "requires-activation", TRUE);
task = fu_install_task_new(device, component);
ret = fu_engine_install(engine,
task,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
FWUPD_FEATURE_FLAG_NONE,
&error);
fu_release_set_device(release, device);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_install_release(engine,
release,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error(error);
g_assert_true(ret);
@ -2045,13 +2202,12 @@ fu_engine_history_inherit(gconstpointer user_data)
fu_progress_reset(progress);
fu_device_set_version_format(device, FWUPD_VERSION_FORMAT_TRIPLET);
fu_device_set_version(device, "1.2.2");
ret = fu_engine_install(engine,
task,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
FWUPD_FEATURE_FLAG_NONE,
&error);
ret = fu_engine_install_release(engine,
release,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error(error);
g_assert_true(ret);
g_object_unref(engine);
@ -2097,7 +2253,7 @@ fu_engine_install_needs_reboot(gconstpointer user_data)
g_autofree gchar *filename = NULL;
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error = NULL;
@ -2155,14 +2311,16 @@ fu_engine_install_needs_reboot(gconstpointer user_data)
/* install it */
g_setenv("FWUPD_PLUGIN_TEST", "requires-reboot", TRUE);
task = fu_install_task_new(device, component);
ret = fu_engine_install(engine,
task,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
FWUPD_FEATURE_FLAG_NONE,
&error);
fu_release_set_device(release, device);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_install_release(engine,
release,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_no_error(error);
g_assert_true(ret);
@ -2185,7 +2343,7 @@ fu_engine_history_error_func(gconstpointer user_data)
g_autoptr(FuDevice) device = fu_device_new_with_context(self->ctx);
g_autoptr(FuEngine) engine = fu_engine_new(FU_APP_FLAGS_NONE);
g_autoptr(FuHistory) history = NULL;
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
g_autoptr(GBytes) blob_cab = NULL;
g_autoptr(GError) error2 = NULL;
@ -2240,14 +2398,16 @@ fu_engine_history_error_func(gconstpointer user_data)
&error);
g_assert_no_error(error);
g_assert_nonnull(component);
task = fu_install_task_new(device, component);
ret = fu_engine_install(engine,
task,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
FWUPD_FEATURE_FLAG_NONE,
&error);
fu_release_set_device(release, device);
ret = fu_release_load(release, component, NULL, FWUPD_INSTALL_FLAG_NONE, &error);
g_assert_no_error(error);
g_assert_true(ret);
ret = fu_engine_install_release(engine,
release,
blob_cab,
progress,
FWUPD_INSTALL_FLAG_NONE,
&error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED);
g_assert_cmpstr(error->message, ==, "device was not in supported mode");
g_assert_false(ret);
@ -3259,7 +3419,7 @@ fu_plugin_composite_func(gconstpointer user_data)
g_autoptr(GBytes) blob = NULL;
g_autoptr(GPtrArray) components = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GPtrArray) install_tasks =
g_autoptr(GPtrArray) releases =
g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
g_autoptr(XbSilo) silo_empty = xb_silo_new();
@ -3361,12 +3521,17 @@ fu_plugin_composite_func(gconstpointer user_data)
/* do any devices pass the requirements */
for (guint j = 0; j < devices->len; j++) {
FuDevice *device = g_ptr_array_index(devices, j);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error_local = NULL;
/* is this component valid for the device */
task = fu_install_task_new(device, component);
if (!fu_engine_check_requirements(engine, request, task, 0, &error_local)) {
fu_release_set_device(release, device);
fu_release_set_request(release, request);
if (!fu_release_load(release,
component,
NULL,
FWUPD_INSTALL_FLAG_NONE,
&error_local)) {
g_debug("requirement on %s:%s failed: %s",
fu_device_get_id(device),
xb_node_query_text(component, "id", NULL),
@ -3374,19 +3539,19 @@ fu_plugin_composite_func(gconstpointer user_data)
continue;
}
g_ptr_array_add(install_tasks, g_steal_pointer(&task));
g_ptr_array_add(releases, g_steal_pointer(&release));
}
}
g_assert_cmpint(install_tasks->len, ==, 3);
g_assert_cmpint(releases->len, ==, 3);
/* install the cab */
ret = fu_engine_install_tasks(engine,
request,
install_tasks,
blob,
progress,
FWUPD_DEVICE_FLAG_NONE,
&error);
ret = fu_engine_install_releases(engine,
request,
releases,
blob,
progress,
FWUPD_DEVICE_FLAG_NONE,
&error);
g_assert_no_error(error);
g_assert_true(ret);
@ -3628,39 +3793,43 @@ fu_progressbar_func(gconstpointer user_data)
}
static gint
fu_install_task_compare_func_cb(gconstpointer a, gconstpointer b)
fu_release_compare_func_cb(gconstpointer a, gconstpointer b)
{
FuInstallTask *task_a = *((FuInstallTask **)a);
FuInstallTask *task_b = *((FuInstallTask **)b);
return fu_install_task_compare(task_a, task_b);
FuRelease *release1 = *((FuRelease **)a);
FuRelease *release2 = *((FuRelease **)b);
return fu_release_compare(release1, release2);
}
static void
fu_install_task_compare_func(gconstpointer user_data)
fu_release_compare_func(gconstpointer user_data)
{
FuDevice *device_tmp;
g_autoptr(GPtrArray) install_tasks = NULL;
g_autoptr(GPtrArray) releases = g_ptr_array_new();
g_autoptr(FuDevice) device1 = fu_device_new();
g_autoptr(FuDevice) device2 = fu_device_new();
g_autoptr(FuDevice) device3 = fu_device_new();
install_tasks = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
g_autoptr(FuRelease) release1 = fu_release_new();
g_autoptr(FuRelease) release2 = fu_release_new();
g_autoptr(FuRelease) release3 = fu_release_new();
fu_device_set_order(device1, 99);
g_ptr_array_add(install_tasks, fu_install_task_new(device1, NULL));
fu_release_set_device(release1, device1);
g_ptr_array_add(releases, release1);
fu_device_set_order(device2, 11);
g_ptr_array_add(install_tasks, fu_install_task_new(device2, NULL));
fu_release_set_device(release2, device2);
g_ptr_array_add(releases, release2);
fu_device_set_order(device3, 33);
g_ptr_array_add(install_tasks, fu_install_task_new(device3, NULL));
fu_release_set_device(release3, device3);
g_ptr_array_add(releases, release3);
/* order the install tasks */
g_ptr_array_sort(install_tasks, fu_install_task_compare_func_cb);
g_assert_cmpint(install_tasks->len, ==, 3);
device_tmp = fu_install_task_get_device(g_ptr_array_index(install_tasks, 0));
g_ptr_array_sort(releases, fu_release_compare_func_cb);
g_assert_cmpint(releases->len, ==, 3);
device_tmp = fu_release_get_device(g_ptr_array_index(releases, 0));
g_assert_cmpint(fu_device_get_order(device_tmp), ==, 11);
device_tmp = fu_install_task_get_device(g_ptr_array_index(install_tasks, 1));
device_tmp = fu_release_get_device(g_ptr_array_index(releases, 1));
g_assert_cmpint(fu_device_get_order(device_tmp), ==, 33);
device_tmp = fu_install_task_get_device(g_ptr_array_index(install_tasks, 2));
device_tmp = fu_release_get_device(g_ptr_array_index(releases, 2));
g_assert_cmpint(fu_device_get_order(device_tmp), ==, 99);
}
@ -3729,7 +3898,7 @@ main(int argc, char **argv)
g_test_add_data_func("/fwupd/device-list{remove-chain}",
self,
fu_device_list_remove_chain_func);
g_test_add_data_func("/fwupd/install-task{compare}", self, fu_install_task_compare_func);
g_test_add_data_func("/fwupd/release{compare}", self, fu_release_compare_func);
g_test_add_data_func("/fwupd/engine{device-unlock}", self, fu_engine_device_unlock_func);
g_test_add_data_func("/fwupd/engine{multiple-releases}",
self,
@ -3772,6 +3941,9 @@ main(int argc, char **argv)
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-version-lowest}",
self,
fu_engine_requirements_version_lowest_func);
g_test_add_data_func("/fwupd/engine{requirements-parent-device}",
self,
fu_engine_requirements_parent_device_func);

View File

@ -1103,11 +1103,11 @@ fu_util_firmware_dump(FuUtilPrivate *priv, gchar **values, GError **error)
}
static gint
fu_util_install_task_sort_cb(gconstpointer a, gconstpointer b)
fu_util_release_sort_cb(gconstpointer a, gconstpointer b)
{
FuInstallTask *task1 = *((FuInstallTask **)a);
FuInstallTask *task2 = *((FuInstallTask **)b);
return fu_install_task_compare(task1, task2);
FuRelease *release1 = *((FuRelease **)a);
FuRelease *release2 = *((FuRelease **)b);
return fu_release_compare(release1, release2);
}
static void
@ -1175,7 +1175,7 @@ fu_util_install(FuUtilPrivate *priv, gchar **values, GError **error)
g_autoptr(GPtrArray) components = NULL;
g_autoptr(GPtrArray) devices_possible = NULL;
g_autoptr(GPtrArray) errors = NULL;
g_autoptr(GPtrArray) install_tasks = NULL;
g_autoptr(GPtrArray) releases = NULL;
g_autoptr(XbSilo) silo = NULL;
/* load engine */
@ -1229,21 +1229,23 @@ fu_util_install(FuUtilPrivate *priv, gchar **values, GError **error)
/* for each component in the silo */
errors = g_ptr_array_new_with_free_func((GDestroyNotify)g_error_free);
install_tasks = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
releases = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
for (guint i = 0; i < components->len; i++) {
XbNode *component = g_ptr_array_index(components, i);
/* do any devices pass the requirements */
for (guint j = 0; j < devices_possible->len; j++) {
FuDevice *device = g_ptr_array_index(devices_possible, j);
g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error_local = NULL;
/* is this component valid for the device */
task = fu_install_task_new(device, component);
fu_release_set_device(release, device);
fu_release_set_request(release, priv->request);
if (!fu_release_load(release, component, NULL, priv->flags, error))
return FALSE;
if (!fu_engine_check_requirements(priv->engine,
priv->request,
task,
release,
priv->flags | FWUPD_INSTALL_FLAG_FORCE,
&error_local)) {
g_debug("first pass requirement on %s:%s failed: %s",
@ -1257,8 +1259,7 @@ fu_util_install(FuUtilPrivate *priv, gchar **values, GError **error)
/* make a second pass using possibly updated version format now */
fu_engine_md_refresh_device_from_component(priv->engine, device, component);
if (!fu_engine_check_requirements(priv->engine,
priv->request,
task,
release,
priv->flags,
&error_local)) {
g_debug("second pass requirement on %s:%s failed: %s",
@ -1273,15 +1274,15 @@ fu_util_install(FuUtilPrivate *priv, gchar **values, GError **error)
fu_device_incorporate_from_component(device, component);
/* success */
g_ptr_array_add(install_tasks, g_steal_pointer(&task));
g_ptr_array_add(releases, g_steal_pointer(&release));
}
}
/* order the install tasks by the device priority */
g_ptr_array_sort(install_tasks, fu_util_install_task_sort_cb);
g_ptr_array_sort(releases, fu_util_release_sort_cb);
/* nothing suitable */
if (install_tasks->len == 0) {
if (releases->len == 0) {
GError *error_tmp = fu_common_error_array_get_best(errors);
g_propagate_error(error, error_tmp);
return FALSE;
@ -1294,13 +1295,13 @@ fu_util_install(FuUtilPrivate *priv, gchar **values, GError **error)
priv);
/* install all the tasks */
if (!fu_engine_install_tasks(priv->engine,
priv->request,
install_tasks,
blob_cab,
priv->progress,
priv->flags,
error))
if (!fu_engine_install_releases(priv->engine,
priv->request,
releases,
blob_cab,
priv->progress,
priv->flags,
error))
return FALSE;
fu_util_display_current_message(priv);

View File

@ -40,7 +40,7 @@ daemon_src = [
'fu-engine-request.c',
'fu-history.c',
'fu-idle.c',
'fu-install-task.c',
'fu-release.c',
'fu-keyring-utils.c',
'fu-plugin-list.c',
'fu-remote-list.c',