diff --git a/src/fu-engine.c b/src/fu-engine.c
index 74f365be2..c7dbeb860 100644
--- a/src/fu-engine.c
+++ b/src/fu-engine.c
@@ -65,6 +65,7 @@
#include "fu-plugin.h"
#include "fu-progress.h"
#include "fu-quirks.h"
+#include "fu-release.h"
#include "fu-remote-list.h"
#include "fu-security-attr.h"
#include "fu-security-attrs-private.h"
@@ -356,120 +357,6 @@ fu_engine_device_changed_cb(FuDeviceList *device_list, FuDevice *device, FuEngin
fu_engine_emit_device_changed(self, fu_device_get_id(device));
}
-/* convert hex and decimal versions to dotted style */
-static gchar *
-fu_engine_get_release_version(FuEngine *self, FuDevice *dev, XbNode *rel, GError **error)
-{
- FwupdVersionFormat fmt = fu_device_get_version_format(dev);
- const gchar *version;
- guint64 ver_uint32;
-
- /* get version */
- version = xb_node_get_attr(rel, "version");
- if (version == NULL) {
- g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "version unset");
- return NULL;
- }
-
- /* already dotted notation */
- if (g_strstr_len(version, -1, ".") != NULL)
- return g_strdup(version);
-
- /* don't touch my version! */
- if (fmt == FWUPD_VERSION_FORMAT_PLAIN)
- return g_strdup(version);
-
- /* parse as integer */
- ver_uint32 = fu_common_strtoull(version);
- if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN || ver_uint32 == 0 || ver_uint32 > G_MAXUINT32)
- return g_strdup(version);
-
- /* convert to dotted decimal */
- return fu_common_version_from_uint32((guint32)ver_uint32, fmt);
-}
-
-static gint
-fu_engine_scheme_compare_cb(gconstpointer a, gconstpointer b, gpointer user_data)
-{
- FuEngine *self = FU_ENGINE(user_data);
- const gchar *location1 = *((const gchar **)a);
- const gchar *location2 = *((const gchar **)b);
- g_autofree gchar *scheme1 = fu_common_uri_get_scheme(location1);
- g_autofree gchar *scheme2 = fu_common_uri_get_scheme(location2);
- guint prio1 = fu_config_get_uri_scheme_prio(self->config, scheme1);
- guint prio2 = fu_config_get_uri_scheme_prio(self->config, scheme2);
- if (prio1 < prio2)
- return -1;
- if (prio1 > prio2)
- return 1;
- return 0;
-}
-
-static gboolean
-fu_engine_set_release_from_artifact(FuEngine *self,
- FwupdRelease *rel,
- FwupdRemote *remote,
- XbNode *artifact,
- GError **error)
-{
- const gchar *filename;
- guint64 size;
- g_autoptr(GPtrArray) locations = NULL;
- g_autoptr(GPtrArray) checksums = NULL;
-
- /* filename */
- filename = xb_node_query_text(artifact, "filename", NULL);
- if (filename != NULL)
- fwupd_release_set_filename(rel, filename);
-
- /* location */
- locations = xb_node_query(artifact, "location", 0, NULL);
- if (locations != NULL) {
- for (guint i = 0; i < locations->len; i++) {
- XbNode *n = g_ptr_array_index(locations, i);
- g_autofree gchar *scheme = NULL;
-
- /* check the scheme is allowed */
- scheme = fu_common_uri_get_scheme(xb_node_get_text(n));
- if (scheme != NULL) {
- guint prio = fu_config_get_uri_scheme_prio(self->config, scheme);
- if (prio == G_MAXUINT)
- continue;
- }
-
- /* build the complete URI */
- if (remote != NULL) {
- g_autofree gchar *uri = NULL;
- uri = fwupd_remote_build_firmware_uri(remote,
- xb_node_get_text(n),
- NULL);
- if (uri != NULL) {
- fwupd_release_add_location(rel, uri);
- continue;
- }
- }
- fwupd_release_add_location(rel, xb_node_get_text(n));
- }
- }
-
- /* checksum */
- checksums = xb_node_query(artifact, "checksum", 0, NULL);
- if (checksums != NULL) {
- for (guint i = 0; i < checksums->len; i++) {
- XbNode *n = g_ptr_array_index(checksums, i);
- fwupd_release_add_checksum(rel, xb_node_get_text(n));
- }
- }
-
- /* size */
- size = xb_node_query_text_as_uint(artifact, "size[@type='installed']", NULL);
- if (size != G_MAXUINT64)
- fwupd_release_set_size(rel, size);
-
- /* success */
- return TRUE;
-}
-
static gchar *
fu_engine_request_get_localized_xpath(FuEngineRequest *request, const gchar *element)
{
@@ -491,11 +378,9 @@ fu_engine_request_get_localized_xpath(FuEngineRequest *request, const gchar *ele
/* add any client-side BKC tags */
static gboolean
-fu_engine_add_local_release_metadata(FuEngine *self,
- FuDevice *dev,
- FwupdRelease *rel,
- GError **error)
+fu_engine_add_local_release_metadata(FuEngine *self, FuRelease *release, GError **error)
{
+ FuDevice *dev = fu_release_get_device(release);
GPtrArray *guids = fu_device_get_guids(dev);
g_autoptr(XbQuery) query = NULL;
g_autoptr(GError) error_query = NULL;
@@ -528,7 +413,7 @@ fu_engine_add_local_release_metadata(FuEngine *self,
xb_value_bindings_bind_str(xb_query_context_get_bindings(&context), 0, guid, NULL);
xb_value_bindings_bind_str(xb_query_context_get_bindings(&context),
1,
- fwupd_release_get_version(rel),
+ fu_release_get_version(release),
NULL);
tags = xb_silo_query_with_context(self->silo, query, &context, &error_local);
#else
@@ -536,7 +421,7 @@ fu_engine_add_local_release_metadata(FuEngine *self,
g_prefix_error(error, "failed to bind GUID: ");
return FALSE;
}
- if (!xb_query_bind_str(query, 1, fwupd_release_get_version(rel), error)) {
+ if (!xb_query_bind_str(query, 1, fu_release_get_version(release), error)) {
g_prefix_error(error, "failed to bind version: ");
return FALSE;
}
@@ -551,7 +436,7 @@ fu_engine_add_local_release_metadata(FuEngine *self,
}
for (guint j = 0; j < tags->len; j++) {
XbNode *tag = g_ptr_array_index(tags, j);
- fwupd_release_add_tag(rel, xb_node_get_text(tag));
+ fu_release_add_tag(release, xb_node_get_text(tag));
}
}
@@ -559,245 +444,49 @@ fu_engine_add_local_release_metadata(FuEngine *self,
return TRUE;
}
-static gboolean
-fu_engine_set_release_from_appstream(FuEngine *self,
- FuEngineRequest *request,
- FuDevice *dev,
- FwupdRelease *rel,
- XbNode *component,
- XbNode *release,
- GError **error)
+static void
+fu_engine_release_remote_id_changed_cb(FuRelease *release, GParamSpec *pspec, FuEngine *self)
{
- FwupdRemote *remote = NULL;
- const gchar *tmp;
- const gchar *remote_id;
- guint64 tmp64;
- g_autofree gchar *description_xpath = NULL;
- g_autofree gchar *name_xpath = NULL;
- g_autofree gchar *namevs_xpath = NULL;
- g_autofree gchar *summary_xpath = NULL;
- g_autofree gchar *version_rel = NULL;
- g_autoptr(GPtrArray) cats = NULL;
- g_autoptr(GPtrArray) tags = NULL;
- g_autoptr(GPtrArray) issues = NULL;
- g_autoptr(XbNode) artifact = NULL;
- g_autoptr(XbNode) description = NULL;
+ FwupdRemote *remote;
+ const gchar *remote_id = fwupd_release_get_remote_id(FWUPD_RELEASE(release));
- /* set from the component */
- tmp = xb_node_query_text(component, "id", NULL);
- if (tmp != NULL)
- fwupd_release_set_appstream_id(rel, tmp);
- tmp = xb_node_query_text(component, "url[@type='homepage']", NULL);
- if (tmp != NULL)
- fwupd_release_set_homepage(rel, tmp);
- tmp = xb_node_query_text(component, "project_license", NULL);
- if (tmp != NULL)
- fwupd_release_set_license(rel, tmp);
- name_xpath = fu_engine_request_get_localized_xpath(request, "name");
- tmp = xb_node_query_text(component, name_xpath, NULL);
- if (tmp != NULL)
- fwupd_release_set_name(rel, tmp);
- summary_xpath = fu_engine_request_get_localized_xpath(request, "summary");
- tmp = xb_node_query_text(component, summary_xpath, NULL);
- if (tmp != NULL)
- fwupd_release_set_summary(rel, tmp);
- namevs_xpath = fu_engine_request_get_localized_xpath(request, "name_variant_suffix");
- tmp = xb_node_query_text(component, namevs_xpath, NULL);
- if (tmp != NULL)
- fwupd_release_set_name_variant_suffix(rel, tmp);
- tmp = xb_node_query_text(component, "branch", NULL);
- if (tmp != NULL)
- fwupd_release_set_branch(rel, tmp);
- tmp = xb_node_query_text(component, "developer_name", NULL);
- if (tmp != NULL)
- fwupd_release_set_vendor(rel, tmp);
+ if (remote_id == NULL)
+ return;
+ remote = fu_remote_list_get_by_id(self->remote_list, remote_id);
+ if (remote == NULL) {
+ g_warning("no remote found for %s", remote_id);
+ return;
+ }
+ fu_release_set_remote(release, remote);
+}
- /* refresh the device and release to the new version format too */
- fu_engine_md_refresh_device_from_component(self, dev, component);
+static gboolean
+fu_engine_load_release(FuEngine *self,
+ FuRelease *release,
+ XbNode *component,
+ XbNode *rel,
+ FwupdInstallFlags install_flags,
+ GError **error)
+{
+ /* load release from XML */
+ fu_release_set_config(release, self->config);
- /* the version is fixed up at runtime */
- version_rel = fu_engine_get_release_version(self, dev, release, error);
- if (version_rel == NULL)
+ /* set the FwupdRemote when the remote ID is set */
+ g_signal_connect(FU_RELEASE(release),
+ "notify::remote-id",
+ G_CALLBACK(fu_engine_release_remote_id_changed_cb),
+ self);
+
+ /* requirements we can check without the daemon */
+ if (!fu_release_load(release, component, rel, install_flags, error))
return FALSE;
- fwupd_release_set_version(rel, version_rel);
- /* optional release ID -- currently a integer but maybe namespaced in the future */
- fwupd_release_set_id(rel, xb_node_get_attr(release, "id"));
-
- /* find the remote */
- remote_id = xb_node_query_text(component, "../custom/value[@key='fwupd::RemoteId']", NULL);
- if (remote_id != NULL) {
- fwupd_release_set_remote_id(rel, remote_id);
- remote = fu_remote_list_get_by_id(self->remote_list, remote_id);
- if (remote == NULL)
- g_warning("no remote found for release %s", version_rel);
- }
- tmp = xb_node_query_text(component, "../custom/value[@key='LVFS::Distributor']", NULL);
- if (g_strcmp0(tmp, "community") == 0)
- fwupd_release_add_flag(rel, FWUPD_RELEASE_FLAG_IS_COMMUNITY);
- artifact = xb_node_query_first(release, "artifacts/artifact", NULL);
- if (artifact != NULL) {
- if (!fu_engine_set_release_from_artifact(self, rel, remote, artifact, error))
- return FALSE;
- }
- description_xpath = fu_engine_request_get_localized_xpath(request, "description");
- description = xb_node_query_first(release, description_xpath, NULL);
- if (description != NULL) {
- g_autofree gchar *xml = NULL;
- g_autoptr(GString) str = NULL;
- xml = xb_node_export(description, XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, NULL);
- str = g_string_new(xml);
- if (fu_device_has_flag(dev, FWUPD_DEVICE_FLAG_AFFECTS_FDE) && request != NULL &&
- !fu_engine_request_has_feature_flag(request, FWUPD_FEATURE_FLAG_FDE_WARNING)) {
- g_string_prepend(
- str,
- "
Some of the platform secrets may be invalidated when "
- "updating this firmware. Please ensure you have the volume "
- "recovery key before continuing.
");
- }
- if (fwupd_release_has_flag(rel, FWUPD_RELEASE_FLAG_IS_COMMUNITY) &&
- request != NULL &&
- !fu_engine_request_has_feature_flag(request,
- FWUPD_FEATURE_FLAG_COMMUNITY_TEXT)) {
- g_string_prepend(
- str,
- "This firmware is provided by LVFS community "
- "members and is not provided (or supported) by the original "
- "hardware vendor. "
- "Installing this update may also void any device warranty.
");
- }
- if (str->len > 0)
- fwupd_release_set_description(rel, str->str);
- }
- if (artifact == NULL) {
- tmp = xb_node_query_text(release, "location", NULL);
- if (tmp != NULL) {
- g_autofree gchar *uri = NULL;
- if (remote != NULL)
- uri = fwupd_remote_build_firmware_uri(remote, tmp, NULL);
- if (uri == NULL)
- uri = g_strdup(tmp);
- fwupd_release_add_location(rel, uri);
- }
- }
- if (fwupd_release_get_locations(rel)->len == 0 && remote != NULL &&
- fwupd_remote_get_kind(remote) == FWUPD_REMOTE_KIND_DIRECTORY) {
- tmp = xb_node_query_text(component,
- "../custom/value[@key='fwupd::FilenameCache']",
- NULL);
- if (tmp != NULL) {
- g_autofree gchar *uri = g_strdup_printf("file://%s", tmp);
- fwupd_release_add_location(rel, uri);
- }
- }
- if (artifact == NULL) {
- tmp = xb_node_query_text(release, "checksum[@target='content']", NULL);
- if (tmp != NULL)
- fwupd_release_set_filename(rel, tmp);
- }
- tmp = xb_node_query_text(release, "url[@type='details']", NULL);
- if (tmp != NULL)
- fwupd_release_set_details_url(rel, tmp);
- tmp = xb_node_query_text(release, "url[@type='source']", NULL);
- if (tmp != NULL)
- fwupd_release_set_source_url(rel, tmp);
- if (artifact == NULL) {
- g_autoptr(GPtrArray) checksums = NULL;
- checksums = xb_node_query(release, "checksum[@target='container']", 0, NULL);
- if (checksums != NULL) {
- for (guint i = 0; i < checksums->len; i++) {
- XbNode *n = g_ptr_array_index(checksums, i);
- if (xb_node_get_text(n) == NULL)
- continue;
- fwupd_release_add_checksum(rel, xb_node_get_text(n));
- }
- }
- }
- if (artifact == NULL) {
- tmp64 = xb_node_query_text_as_uint(release, "size[@type='installed']", NULL);
- if (tmp64 != G_MAXUINT64)
- fwupd_release_set_size(rel, tmp64);
- }
- if (fwupd_release_get_size(rel) == 0) {
- GBytes *sz = xb_node_get_data(release, "fwupd::ReleaseSize");
- if (sz != NULL) {
- const guint64 *sizeptr = g_bytes_get_data(sz, NULL);
- fwupd_release_set_size(rel, *sizeptr);
- }
- }
- tmp = xb_node_get_attr(release, "urgency");
- if (tmp != NULL)
- fwupd_release_set_urgency(rel, fwupd_release_urgency_from_string(tmp));
- tmp64 = xb_node_get_attr_as_uint(release, "install_duration");
- if (tmp64 != G_MAXUINT64)
- fwupd_release_set_install_duration(rel, tmp64);
- tmp64 = xb_node_get_attr_as_uint(release, "timestamp");
- if (tmp64 != G_MAXUINT64)
- fwupd_release_set_created(rel, tmp64);
- cats = xb_node_query(component, "categories/category", 0, NULL);
- if (cats != NULL) {
- for (guint i = 0; i < cats->len; i++) {
- XbNode *n = g_ptr_array_index(cats, i);
- fwupd_release_add_category(rel, xb_node_get_text(n));
- }
- }
- tags = xb_node_query(component, "tags/tag[@namespace=$'lvfs']", 0, NULL);
- if (tags != NULL) {
- for (guint i = 0; i < tags->len; i++) {
- XbNode *tag = g_ptr_array_index(tags, i);
- fwupd_release_add_tag(rel, xb_node_get_text(tag));
- }
- }
- issues = xb_node_query(component, "issues/issue", 0, NULL);
- if (issues != NULL) {
- for (guint i = 0; i < issues->len; i++) {
- XbNode *n = g_ptr_array_index(issues, i);
- fwupd_release_add_issue(rel, xb_node_get_text(n));
- }
- }
- tmp = xb_node_query_text(component, "screenshots/screenshot/caption", NULL);
- if (tmp != NULL)
- fwupd_release_set_detach_caption(rel, tmp);
- tmp = xb_node_query_text(component, "screenshots/screenshot/image", NULL);
- if (tmp != NULL) {
- if (remote != NULL) {
- g_autofree gchar *img = NULL;
- img = fwupd_remote_build_firmware_uri(remote, tmp, error);
- if (img == NULL)
- return FALSE;
- fwupd_release_set_detach_image(rel, img);
- } else {
- fwupd_release_set_detach_image(rel, tmp);
- }
- }
- tmp = xb_node_query_text(component, "custom/value[@key='LVFS::UpdateProtocol']", NULL);
- if (tmp != NULL)
- fwupd_release_set_protocol(rel, tmp);
- tmp = xb_node_query_text(component, "custom/value[@key='LVFS::UpdateMessage']", NULL);
- if (tmp != NULL)
- fwupd_release_set_update_message(rel, tmp);
- tmp = xb_node_query_text(component, "custom/value[@key='LVFS::UpdateImage']", NULL);
- if (tmp != NULL) {
- if (remote != NULL) {
- g_autofree gchar *img = NULL;
- img = fwupd_remote_build_firmware_uri(remote, tmp, error);
- if (img == NULL)
- return FALSE;
- fwupd_release_set_update_image(rel, img);
- } else {
- fwupd_release_set_update_image(rel, tmp);
- }
- }
- if (xb_node_get_attr(component, "date_eol") != NULL)
- fu_device_add_flag(dev, FWUPD_DEVICE_FLAG_END_OF_LIFE);
-
- /* sort the locations by scheme */
- g_ptr_array_sort_with_data(fwupd_release_get_locations(rel),
- fu_engine_scheme_compare_cb,
- self);
+ /* additional requirements */
+ if (!fu_engine_check_requirements(self, release, install_flags, error))
+ return FALSE;
/* add any client-side BKC tags */
- if (!fu_engine_add_local_release_metadata(self, dev, rel, error))
+ if (!fu_engine_add_local_release_metadata(self, release, error))
return FALSE;
/* success */
@@ -1845,12 +1534,14 @@ fu_engine_check_requirement_client(FuEngine *self,
static gboolean
fu_engine_check_requirement(FuEngine *self,
- FuEngineRequest *request,
+ FuRelease *release,
XbNode *req,
- FuDevice *device,
FwupdInstallFlags flags,
GError **error)
{
+ FuDevice *device = fu_release_get_device(release);
+ FuEngineRequest *request = fu_release_get_request(release);
+
/* ensure component requirement */
if (g_strcmp0(xb_node_get_element(req), "id") == 0)
return fu_engine_check_requirement_id(self, req, error);
@@ -1880,10 +1571,10 @@ fu_engine_check_requirement(FuEngine *self,
}
gboolean
-fu_engine_check_trust(FuEngine *self, FuInstallTask *task, GError **error)
+fu_engine_check_trust(FuEngine *self, FuRelease *release, GError **error)
{
if (fu_config_get_only_trusted(self->config) &&
- (fu_install_task_get_trust_flags(task) & FWUPD_TRUST_FLAG_PAYLOAD) == 0) {
+ (fu_release_get_trust_flags(release) & FWUPD_TRUST_FLAG_PAYLOAD) == 0) {
g_autofree gchar *sysconfdir = fu_common_get_path(FU_PATH_KIND_SYSCONFDIR_PKG);
g_autofree gchar *fn = g_build_filename(sysconfdir, "daemon.conf", NULL);
g_set_error(error,
@@ -1899,14 +1590,13 @@ fu_engine_check_trust(FuEngine *self, FuInstallTask *task, GError **error)
static gboolean
fu_engine_check_soft_requirement(FuEngine *self,
- FuEngineRequest *request,
+ FuRelease *release,
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 (!fu_engine_check_requirement(self, release, req, flags, &error_local)) {
if (flags & FWUPD_INSTALL_FLAG_FORCE) {
g_debug("ignoring soft-requirement due to --force: %s",
error_local->message);
@@ -1920,73 +1610,30 @@ fu_engine_check_soft_requirement(FuEngine *self,
gboolean
fu_engine_check_requirements(FuEngine *self,
- FuEngineRequest *request,
- FuInstallTask *task,
+ FuRelease *release,
FwupdInstallFlags flags,
GError **error)
{
- FuDevice *device = fu_install_task_get_device(task);
- const gchar *protocol;
- g_autoptr(GError) error_local = NULL;
- g_autoptr(GPtrArray) reqs_hard = NULL;
- g_autoptr(GPtrArray) reqs_soft = NULL;
+ GPtrArray *reqs;
- /* all install task checks require a device */
- if (device != NULL &&
- fu_engine_request_get_kind(request) == FU_ENGINE_REQUEST_KIND_ACTIVE) {
- if (!fu_install_task_check_requirements(task, flags, error))
- return FALSE;
- }
-
- /* do engine checks */
- reqs_hard =
- xb_node_query(fu_install_task_get_component(task), "requires/*", 0, &error_local);
- if (reqs_hard != NULL) {
- for (guint i = 0; i < reqs_hard->len; i++) {
- XbNode *req = g_ptr_array_index(reqs_hard, i);
- if (!fu_engine_check_requirement(self, request, req, device, flags, error))
+ /* hard requirements */
+ reqs = fu_release_get_hard_reqs(release);
+ if (reqs != NULL) {
+ for (guint i = 0; i < reqs->len; i++) {
+ XbNode *req = g_ptr_array_index(reqs, i);
+ if (!fu_engine_check_requirement(self, release, req, 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;
}
/* soft requirements */
- g_clear_error(&error_local);
- reqs_soft = xb_node_query(fu_install_task_get_component(task),
- "suggests/*|recommends/*",
- 0,
- &error_local);
- if (reqs_soft != NULL) {
- for (guint i = 0; i < reqs_soft->len; i++) {
- XbNode *req = g_ptr_array_index(reqs_soft, i);
- if (!fu_engine_check_soft_requirement(self,
- request,
- req,
- device,
- flags,
- error))
+ reqs = fu_release_get_soft_reqs(release);
+ 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, release, req, 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;
- }
-
- /* ensure protocol is registered with the device */
- protocol = xb_node_query_text(fu_install_task_get_component(task),
- "custom/value[@key='LVFS::UpdateProtocol']",
- NULL);
- if (protocol != NULL && !fu_device_has_protocol(device, protocol)) {
- g_set_error(error,
- FWUPD_ERROR,
- FWUPD_ERROR_NOT_SUPPORTED,
- "protocol %s is not supported by device",
- protocol);
- return FALSE;
}
/* success */
@@ -2281,11 +1928,22 @@ fu_engine_composite_cleanup(FuEngine *self, GPtrArray *devices, GError **error)
return TRUE;
}
+static gint
+fu_engine_sort_release_versions_cb(gconstpointer a, gconstpointer b)
+{
+ FuRelease *na = *((FuRelease **)a);
+ FuRelease *nb = *((FuRelease **)b);
+ FuDevice *device = fu_release_get_device(na);
+ const gchar *va = fu_release_get_version(na);
+ const gchar *vb = fu_release_get_version(nb);
+ return fu_common_vercmp_full(va, vb, fu_device_get_version_format(device));
+}
+
/**
- * fu_engine_install_tasks:
+ * fu_engine_install_releases:
* @self: a #FuEngine
* @request: a #FuEngineRequest
- * @install_tasks: (element-type FuInstallTask): a device
+ * @releases: (element-type FuRelease): a device
* @blob_cab: the #GBytes of the .cab file
* @flags: install flags, e.g. %FWUPD_DEVICE_FLAG_UPDATABLE
* @error: (nullable): optional return location for an error
@@ -2299,15 +1957,14 @@ fu_engine_composite_cleanup(FuEngine *self, GPtrArray *devices, GError **error)
* Returns: %TRUE for success
**/
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)
{
- FwupdFeatureFlags feature_flags = fu_engine_request_get_feature_flags(request);
g_autoptr(FuIdleLocker) locker = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GPtrArray) devices_new = NULL;
@@ -2316,14 +1973,17 @@ fu_engine_install_tasks(FuEngine *self,
locker = fu_idle_locker_new(self->idle, "update");
g_assert(locker != NULL);
+ /* install these in the right order */
+ g_ptr_array_sort(releases, fu_engine_sort_release_versions_cb);
+
/* notify the plugins about the composite action */
devices = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
- for (guint i = 0; i < install_tasks->len; i++) {
- FuInstallTask *task = g_ptr_array_index(install_tasks, i);
+ for (guint i = 0; i < releases->len; i++) {
+ FuRelease *release = g_ptr_array_index(releases, i);
g_debug("composite update %u: %s",
i + 1,
- fu_device_get_id(fu_install_task_get_device(task)));
- g_ptr_array_add(devices, g_object_ref(fu_install_task_get_device(task)));
+ fu_device_get_id(fu_release_get_device(release)));
+ g_ptr_array_add(devices, g_object_ref(fu_release_get_device(release)));
}
if (!fu_engine_composite_prepare(self, devices, error)) {
g_prefix_error(error, "failed to prepare composite action: ");
@@ -2331,16 +1991,15 @@ fu_engine_install_tasks(FuEngine *self,
}
/* all authenticated, so install all the things */
- fu_progress_set_steps(progress, install_tasks->len);
- for (guint i = 0; i < install_tasks->len; i++) {
- FuInstallTask *task = g_ptr_array_index(install_tasks, i);
- if (!fu_engine_install(self,
- task,
- blob_cab,
- fu_progress_get_child(progress),
- flags,
- feature_flags,
- error)) {
+ fu_progress_set_steps(progress, releases->len);
+ for (guint i = 0; i < releases->len; i++) {
+ FuRelease *release = g_ptr_array_index(releases, i);
+ if (!fu_engine_install_release(self,
+ release,
+ blob_cab,
+ fu_progress_get_child(progress),
+ flags,
+ error)) {
g_autoptr(GError) error_local = NULL;
if (!fu_engine_composite_cleanup(self, devices, &error_local)) {
g_warning("failed to cleanup failed composite action: %s",
@@ -2352,9 +2011,9 @@ fu_engine_install_tasks(FuEngine *self,
}
/* set all the device statuses back to unknown */
- for (guint i = 0; i < install_tasks->len; i++) {
- FuInstallTask *task = g_ptr_array_index(install_tasks, i);
- FuDevice *device = fu_install_task_get_device(task);
+ for (guint i = 0; i < releases->len; i++) {
+ FuRelease *release = g_ptr_array_index(releases, i);
+ FuDevice *device = fu_release_get_device(release);
fwupd_device_set_status(FWUPD_DEVICE(device), FWUPD_STATUS_UNKNOWN);
}
@@ -2385,27 +2044,23 @@ fu_engine_install_tasks(FuEngine *self,
return TRUE;
}
-static FwupdRelease *
-fu_engine_create_release_metadata(FuEngine *self,
- FuDevice *device,
- FuPlugin *plugin,
- GError **error)
+static gboolean
+fu_engine_add_release_metadata(FuEngine *self, FuRelease *release, FuPlugin *plugin, GError **error)
{
GPtrArray *metadata_sources;
- g_autoptr(FwupdRelease) release = fwupd_release_new();
g_autoptr(GHashTable) metadata_device = NULL;
g_autoptr(GHashTable) metadata_hash = NULL;
/* build the version metadata */
metadata_hash = fu_engine_get_report_metadata(self, error);
if (metadata_hash == NULL)
- return NULL;
- fwupd_release_add_metadata(release, metadata_hash);
+ return FALSE;
+ fu_release_add_metadata(release, metadata_hash);
if (fu_plugin_get_report_metadata(plugin) != NULL)
- fwupd_release_add_metadata(release, fu_plugin_get_report_metadata(plugin));
- metadata_device = fu_device_report_metadata_pre(device);
+ fu_release_add_metadata(release, fu_plugin_get_report_metadata(plugin));
+ metadata_device = fu_device_report_metadata_pre(fu_release_get_device(release));
if (metadata_device != NULL)
- fwupd_release_add_metadata(release, metadata_device);
+ fu_release_add_metadata(release, metadata_device);
/* allow other plugins to contribute metadata too */
metadata_sources = fu_plugin_get_rules(plugin, FU_PLUGIN_RULE_METADATA_SOURCE);
@@ -2426,12 +2081,12 @@ fu_engine_create_release_metadata(FuEngine *self,
}
if (fu_plugin_get_report_metadata(plugin_tmp) != NULL) {
fwupd_release_add_metadata(
- release,
+ FWUPD_RELEASE(release),
fu_plugin_get_report_metadata(plugin_tmp));
}
}
}
- return g_steal_pointer(&release);
+ return TRUE;
}
static gboolean
@@ -2605,32 +2260,92 @@ fu_engine_schedule_update(FuEngine *self,
return fu_engine_offline_setup(error);
}
-static gboolean
+/**
+ * fu_engine_install_release:
+ * @self: a #FuEngine
+ * @release: a #FuRelease
+ * @blob_cab: the #GBytes of the .cab file
+ * @progress: a #FuProgress
+ * @flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_OLDER
+ * @error: (nullable): optional return location for an error
+ *
+ * Installs a specific release on a device.
+ *
+ * By this point all the requirements and tests should have been done in
+ * fu_engine_check_requirements() so this should not fail before running
+ * the plugin loader.
+ *
+ * Returns: %TRUE for success
+ **/
+gboolean
fu_engine_install_release(FuEngine *self,
- FuDevice *device_orig,
- XbNode *component,
- XbNode *rel,
+ FuRelease *release,
+ GBytes *blob_cab,
FuProgress *progress,
FwupdInstallFlags flags,
- FwupdFeatureFlags feature_flags,
GError **error)
{
+ FuDevice *device_orig = fu_release_get_device(release);
+ FuEngineRequest *request = fu_release_get_request(release);
FuPlugin *plugin;
+ FwupdFeatureFlags feature_flags = FWUPD_FEATURE_FLAG_NONE;
FwupdVersionFormat fmt;
GBytes *blob_fw;
const gchar *tmp;
+ const gchar *version_rel;
g_autofree gchar *version_orig = NULL;
- g_autofree gchar *version_rel = NULL;
+ g_autoptr(FuDevice) device = NULL;
g_autoptr(FuDevice) device_tmp = NULL;
- g_autoptr(FuDevice) device = g_object_ref(device_orig);
g_autoptr(GBytes) blob_fw2 = NULL;
g_autoptr(GError) error_local = NULL;
+ g_return_val_if_fail(FU_IS_ENGINE(self), FALSE);
+ g_return_val_if_fail(FU_IS_RELEASE(release), FALSE);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), FALSE);
+ g_return_val_if_fail(blob_cab != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* optional for tests */
+ if (request != NULL)
+ feature_flags = fu_engine_request_get_feature_flags(request);
+
+ /* not in bootloader mode */
+ device = g_object_ref(fu_release_get_device(release));
+ if (!fu_device_has_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
+ /* both optional; the plugin can specify a fallback */
+ tmp = fwupd_release_get_detach_caption(FWUPD_RELEASE(release));
+ if (tmp != NULL)
+ fu_device_set_update_message(device, tmp);
+ tmp = fwupd_release_get_detach_image(FWUPD_RELEASE(release));
+ if (tmp != NULL)
+ fu_device_set_update_image(device, tmp);
+ }
+
+ /* schedule this for the next reboot if not in system-update.target,
+ * but first check if allowed on battery power */
+ if ((flags & FWUPD_INSTALL_FLAG_OFFLINE) > 0 && !fu_engine_is_running_offline(self)) {
+ FuPlugin *plugin_tmp =
+ fu_plugin_list_find_by_name(self->plugin_list, "upower", NULL);
+ if (plugin_tmp != NULL) {
+ if (!fu_plugin_runner_prepare(plugin_tmp, device, flags, error))
+ return FALSE;
+ }
+ fu_progress_set_status(progress, FWUPD_STATUS_SCHEDULING);
+ if (!fu_engine_add_release_metadata(self, release, plugin_tmp, error))
+ return FALSE;
+ return fu_engine_schedule_update(self,
+ device,
+ FWUPD_RELEASE(release),
+ blob_cab,
+ flags,
+ error);
+ }
+
/* set this for the callback */
self->write_history = (flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0;
/* get per-release firmware blob */
- blob_fw = xb_node_get_data(rel, "fwupd::FirmwareBlob");
+ blob_fw = fu_release_get_fw_blob(release);
if (blob_fw == NULL) {
g_set_error_literal(error,
FWUPD_ERROR,
@@ -2640,12 +2355,12 @@ fu_engine_install_release(FuEngine *self,
}
/* use a bubblewrap helper script to build the firmware */
- tmp = g_object_get_data(G_OBJECT(component), "fwupd::BuilderScript");
+ tmp = fu_release_get_builder_script(release);
if (tmp != NULL) {
- const gchar *tmp2 = g_object_get_data(G_OBJECT(component), "fwupd::BuilderOutput");
- if (tmp2 == NULL)
- tmp2 = "firmware.bin";
- blob_fw2 = fu_common_firmware_builder(blob_fw, tmp, tmp2, error);
+ blob_fw2 = fu_common_firmware_builder(blob_fw,
+ tmp,
+ fu_release_get_builder_output(release),
+ error);
if (blob_fw2 == NULL)
return FALSE;
} else {
@@ -2658,27 +2373,11 @@ fu_engine_install_release(FuEngine *self,
if (plugin == NULL)
return FALSE;
- /* schedule this for the next reboot if not in system-update.target,
- * but first check if allowed on battery power */
- version_rel = fu_engine_get_release_version(self, device, rel, error);
- if (version_rel == NULL) {
- g_prefix_error(error, "failed to get release version: ");
- return FALSE;
- }
-
/* add device to database */
if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0) {
- g_autoptr(FwupdRelease) release_tmp = NULL;
- release_tmp = fu_engine_create_release_metadata(self, device, plugin, error);
- if (release_tmp == NULL)
+ if (!fu_engine_add_release_metadata(self, release, plugin, error))
return FALSE;
- tmp = xb_node_query_text(component,
- "releases/release/checksum[@target='container']",
- NULL);
- if (tmp != NULL)
- fwupd_release_add_checksum(release_tmp, tmp);
- fwupd_release_set_version(release_tmp, version_rel);
- if (!fu_history_add_device(self->history, device, release_tmp, error))
+ if (!fu_history_add_device(self->history, device, FWUPD_RELEASE(release), error))
return FALSE;
}
@@ -2722,6 +2421,7 @@ fu_engine_install_release(FuEngine *self,
/* for online updates, verify the version changed if not a re-install */
fmt = fu_device_get_version_format(device);
+ version_rel = fu_release_get_version(release);
if (version_rel != NULL && fu_common_vercmp_full(version_orig, version_rel, fmt) != 0 &&
fu_common_vercmp_full(version_orig, fu_device_get_version(device), fmt) == 0 &&
!fu_device_has_flag(device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) {
@@ -2733,200 +2433,6 @@ fu_engine_install_release(FuEngine *self,
fu_device_set_update_error(device, str);
}
- return TRUE;
-}
-
-typedef struct {
- gboolean ret;
- GError **error;
- FuEngine *self;
- FuDevice *device;
-} FuEngineSortHelper;
-
-static gint
-fu_engine_sort_release_versions_cb(gconstpointer a, gconstpointer b, gpointer user_data)
-{
- FuEngineSortHelper *helper = (FuEngineSortHelper *)user_data;
- XbNode *na = *((XbNode **)a);
- XbNode *nb = *((XbNode **)b);
- g_autofree gchar *va = NULL;
- g_autofree gchar *vb = NULL;
-
- /* already failed */
- if (!helper->ret)
- return 0;
-
- /* get the semver from the release */
- va = fu_engine_get_release_version(helper->self, helper->device, na, helper->error);
- if (va == NULL) {
- g_prefix_error(helper->error, "failed to get release version: ");
- return 0;
- }
- vb = fu_engine_get_release_version(helper->self, helper->device, nb, helper->error);
- if (vb == NULL) {
- g_prefix_error(helper->error, "failed to get release version: ");
- return 0;
- }
- return fu_common_vercmp_full(va, vb, fu_device_get_version_format(helper->device));
-}
-
-static gboolean
-fu_engine_sort_releases(FuEngine *self, FuDevice *device, GPtrArray *rels, GError **error)
-{
- FuEngineSortHelper helper = {
- .ret = TRUE,
- .self = self,
- .device = device,
- .error = error,
- };
- g_ptr_array_sort_with_data(rels, fu_engine_sort_release_versions_cb, &helper);
- return helper.ret;
-}
-
-/**
- * fu_engine_install:
- * @self: a #FuEngine
- * @task: a #FuInstallTask
- * @blob_cab: the #GBytes of the .cab file
- * @progress: a #FuProgress
- * @flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_OLDER
- * @feature_flags: feature flags, e.g. %FWUPD_FEATURE_FLAG_NONE
- * @error: (nullable): optional return location for an error
- *
- * Installs a specific firmware file on a device.
- *
- * By this point all the requirements and tests should have been done in
- * fu_engine_check_requirements() so this should not fail before running
- * the plugin loader.
- *
- * Returns: %TRUE for success
- **/
-gboolean
-fu_engine_install(FuEngine *self,
- FuInstallTask *task,
- GBytes *blob_cab,
- FuProgress *progress,
- FwupdInstallFlags flags,
- FwupdFeatureFlags feature_flags,
- GError **error)
-{
- XbNode *component = fu_install_task_get_component(task);
- g_autoptr(FuDevice) device = NULL;
- g_autoptr(GError) error_local = NULL;
- g_autoptr(XbNode) rel_newest = NULL;
-#if LIBXMLB_CHECK_VERSION(0, 2, 0)
- g_autoptr(XbQuery) query = NULL;
-#endif
-
- g_return_val_if_fail(FU_IS_ENGINE(self), FALSE);
- g_return_val_if_fail(FU_IS_PROGRESS(progress), FALSE);
- g_return_val_if_fail(XB_IS_NODE(component), FALSE);
- g_return_val_if_fail(blob_cab != NULL, FALSE);
- g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
-
- /* not in bootloader mode */
- device = g_object_ref(fu_install_task_get_device(task));
- if (!fu_device_has_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) {
- const gchar *tmp = NULL;
-
- /* both optional; the plugin can specify a fallback */
- tmp = xb_node_query_text(component, "screenshots/screenshot/caption", NULL);
- if (tmp != NULL)
- fu_device_set_update_message(device, tmp);
- tmp = xb_node_query_text(component, "screenshots/screenshot/image", NULL);
- if (tmp != NULL)
- fu_device_set_update_image(device, tmp);
- }
-
- /* get the newest version */
-#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;
- rel_newest = xb_node_query_first_full(component, query, &error_local);
-#else
- rel_newest = xb_node_query_first(component, "releases/release", &error_local);
-#endif
- if (rel_newest == NULL) {
- g_set_error(error,
- FWUPD_ERROR,
- FWUPD_ERROR_INVALID_FILE,
- "No releases in the firmware component: %s",
- error_local->message);
- return FALSE;
- }
-
- /* schedule this for the next reboot if not in system-update.target,
- * but first check if allowed on battery power */
- if ((flags & FWUPD_INSTALL_FLAG_OFFLINE) > 0 && !fu_engine_is_running_offline(self)) {
- FuPlugin *plugin;
- g_autoptr(FwupdRelease) release_tmp = NULL;
- g_autofree gchar *version_rel = NULL;
- version_rel = fu_engine_get_release_version(self, device, rel_newest, error);
- if (version_rel == NULL) {
- g_prefix_error(error, "failed to get release version: ");
- return FALSE;
- }
- plugin = fu_plugin_list_find_by_name(self->plugin_list, "upower", NULL);
- if (plugin != NULL) {
- if (!fu_plugin_runner_prepare(plugin, device, flags, error))
- return FALSE;
- }
- fu_progress_set_status(progress, FWUPD_STATUS_SCHEDULING);
- release_tmp = fu_engine_create_release_metadata(self, device, plugin, error);
- if (release_tmp == NULL)
- return FALSE;
- fwupd_release_set_version(release_tmp, version_rel);
- return fu_engine_schedule_update(self, device, release_tmp, blob_cab, flags, error);
- }
-
- /* install each intermediate release, or install only the newest version */
- if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES)) {
- g_autoptr(GPtrArray) rels = NULL;
-#if LIBXMLB_CHECK_VERSION(0, 2, 0)
- rels = xb_node_query_full(component, query, &error_local);
-#else
- rels = xb_node_query(component, "releases/release", 0, &error_local);
-#endif
- if (rels == NULL) {
- g_set_error(error,
- FWUPD_ERROR,
- FWUPD_ERROR_INVALID_FILE,
- "No releases in the firmware component: %s",
- error_local->message);
- return FALSE;
- }
- if (!fu_engine_sort_releases(self, device, rels, error))
- return FALSE;
- fu_progress_set_steps(progress, rels->len);
- for (guint i = 0; i < rels->len; i++) {
- XbNode *rel = g_ptr_array_index(rels, i);
- if (!fu_engine_install_release(self,
- device,
- component,
- rel,
- fu_progress_get_child(progress),
- flags,
- feature_flags,
- error))
- return FALSE;
- fu_progress_step_done(progress);
- }
- } else {
- if (!fu_engine_install_release(self,
- device,
- component,
- rel_newest,
- progress,
- flags,
- feature_flags,
- error))
- return FALSE;
- }
-
/* mark success unless needs a reboot */
if (fu_device_get_update_state(device) != FWUPD_UPDATE_STATE_NEEDS_REBOOT)
fu_device_set_update_state(device, FWUPD_UPDATE_STATE_SUCCESS);
@@ -4512,15 +4018,14 @@ fu_engine_get_result_from_component(FuEngine *self,
{
FwupdReleaseFlags release_flags = FWUPD_RELEASE_FLAG_NONE;
g_autofree gchar *description_xpath = NULL;
- g_autoptr(FuInstallTask) task = NULL;
g_autoptr(FuDevice) dev = NULL;
- g_autoptr(FwupdRelease) rel = NULL;
+ g_autoptr(FuRelease) release = NULL;
g_autoptr(GError) error_local = NULL;
g_autoptr(GError) error_reqs = NULL;
g_autoptr(GPtrArray) provides = NULL;
g_autoptr(GPtrArray) tags = NULL;
g_autoptr(XbNode) description = NULL;
- g_autoptr(XbNode) release = NULL;
+ g_autoptr(XbNode) rel = NULL;
#if LIBXMLB_CHECK_VERSION(0, 2, 0)
g_autoptr(XbQuery) query = NULL;
#endif
@@ -4573,17 +4078,23 @@ fu_engine_get_result_from_component(FuEngine *self,
if (tags != NULL) {
for (guint i = 0; i < tags->len; i++) {
XbNode *tag = g_ptr_array_index(tags, i);
- fwupd_release_add_tag(rel, xb_node_get_text(tag));
+ fu_release_add_tag(release, xb_node_get_text(tag));
}
}
+ /* add EOL flag */
+ if (xb_node_get_attr(component, "date_eol") != NULL)
+ fu_device_add_flag(dev, FWUPD_DEVICE_FLAG_END_OF_LIFE);
+
/* check we can install it */
- task = fu_install_task_new(NULL, component);
- if (!fu_engine_check_requirements(self,
- request,
- task,
- FWUPD_INSTALL_FLAG_IGNORE_VID_PID,
- &error_reqs)) {
+ release = fu_release_new();
+ fu_release_set_request(release, request);
+ if (!fu_engine_load_release(self,
+ release,
+ component,
+ NULL,
+ FWUPD_INSTALL_FLAG_IGNORE_VID_PID,
+ &error_reqs)) {
fu_device_inhibit(dev, "failed-reqs", error_reqs->message);
/* continue */
}
@@ -4596,11 +4107,11 @@ fu_engine_get_result_from_component(FuEngine *self,
error);
if (query == NULL)
return NULL;
- release = xb_node_query_first_full(component, query, &error_local);
+ rel = xb_node_query_first_full(component, query, &error_local);
#else
- release = xb_node_query_first(component, "releases/release", &error_local);
+ rel = xb_node_query_first(component, "releases/release", &error_local);
#endif
- if (release == NULL) {
+ if (rel == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
@@ -4608,7 +4119,7 @@ fu_engine_get_result_from_component(FuEngine *self,
error_local->message);
return NULL;
}
- if (!fu_keyring_get_release_flags(release, &release_flags, &error_local)) {
+ if (!fu_keyring_get_release_flags(rel, &release_flags, &error_local)) {
if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
g_warning("Ignoring verification: %s", error_local->message);
} else {
@@ -4626,17 +4137,17 @@ fu_engine_get_result_from_component(FuEngine *self,
if (xml != NULL)
fu_device_set_description(dev, xml);
}
- rel = fwupd_release_new();
- fwupd_release_set_flags(rel, release_flags);
- if (!fu_engine_set_release_from_appstream(self,
- request,
- dev,
- rel,
- component,
- release,
- error))
+
+ /* refresh the device to the new version format too */
+ fu_engine_md_refresh_device_from_component(self, dev, component);
+
+ release = fu_release_new();
+ fu_release_set_request(release, request);
+ fu_release_set_device(release, dev);
+ fwupd_release_set_flags(FWUPD_RELEASE(release), release_flags);
+ if (!fu_engine_load_release(self, release, component, rel, FWUPD_INSTALL_FLAG_NONE, error))
return NULL;
- fu_device_add_release(dev, rel);
+ fu_device_add_release(dev, FWUPD_RELEASE(release));
return g_steal_pointer(&dev);
}
@@ -4734,17 +4245,21 @@ fu_engine_get_details(FuEngine *self, FuEngineRequest *request, gint fd, GError
/* if this matched a device on the system, ensure all the
* requirements passed before setting UPDATABLE */
if (fu_device_has_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE)) {
- g_autoptr(FuInstallTask) task = fu_install_task_new(dev, component);
+ g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error_req = NULL;
- if (!fu_engine_check_requirements(
- self,
- request,
- task,
- FWUPD_INSTALL_FLAG_OFFLINE | FWUPD_INSTALL_FLAG_IGNORE_VID_PID |
- FWUPD_INSTALL_FLAG_ALLOW_REINSTALL |
- FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH |
- FWUPD_INSTALL_FLAG_ALLOW_OLDER,
- &error_req)) {
+ FwupdInstallFlags install_flags =
+ FWUPD_INSTALL_FLAG_OFFLINE | FWUPD_INSTALL_FLAG_IGNORE_VID_PID |
+ FWUPD_INSTALL_FLAG_ALLOW_REINSTALL |
+ FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH | FWUPD_INSTALL_FLAG_ALLOW_OLDER;
+
+ fu_release_set_device(release, dev);
+ fu_release_set_request(release, request);
+ if (!fu_engine_load_release(self,
+ release,
+ component,
+ NULL,
+ install_flags,
+ &error_req)) {
g_debug("%s failed requirement checks: %s",
fu_device_get_id(dev),
error_req->message);
@@ -5078,9 +4593,9 @@ fu_engine_check_release_is_approved(FuEngine *self, FwupdRelease *rel)
}
static gboolean
-fu_engine_check_release_is_blocked(FuEngine *self, FwupdRelease *rel)
+fu_engine_check_release_is_blocked(FuEngine *self, FuRelease *release)
{
- GPtrArray *csums = fwupd_release_get_checksums(rel);
+ GPtrArray *csums = fu_release_get_checksums(release);
if (self->blocked_firmware == NULL)
return FALSE;
for (guint i = 0; i < csums->len; i++) {
@@ -5102,18 +4617,11 @@ fu_engine_add_releases_for_device_component(FuEngine *self,
FwupdFeatureFlags feature_flags;
FwupdVersionFormat fmt = fu_device_get_version_format(device);
g_autoptr(GError) error_local = NULL;
- g_autoptr(FuInstallTask) task = fu_install_task_new(device, component);
g_autoptr(GPtrArray) releases_tmp = NULL;
-
- if (!fu_engine_check_requirements(
- self,
- request,
- task,
- FWUPD_INSTALL_FLAG_OFFLINE | FWUPD_INSTALL_FLAG_IGNORE_VID_PID |
- FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH | FWUPD_INSTALL_FLAG_ALLOW_REINSTALL |
- FWUPD_INSTALL_FLAG_ALLOW_OLDER,
- error))
- return FALSE;
+ FwupdInstallFlags install_flags =
+ FWUPD_INSTALL_FLAG_OFFLINE | FWUPD_INSTALL_FLAG_IGNORE_VID_PID |
+ FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH | FWUPD_INSTALL_FLAG_ALLOW_REINSTALL |
+ FWUPD_INSTALL_FLAG_ALLOW_OLDER;
/* get all releases */
releases_tmp = xb_node_query(component, "releases/release", 0, &error_local);
@@ -5127,96 +4635,98 @@ fu_engine_add_releases_for_device_component(FuEngine *self,
}
feature_flags = fu_engine_request_get_feature_flags(request);
for (guint i = 0; i < releases_tmp->len; i++) {
- XbNode *release = g_ptr_array_index(releases_tmp, i);
+ XbNode *rel = g_ptr_array_index(releases_tmp, i);
const gchar *remote_id;
const gchar *update_message;
const gchar *update_image;
gint vercmp;
GPtrArray *checksums;
GPtrArray *locations;
- g_autoptr(FwupdRelease) rel = fwupd_release_new();
+ g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error_loop = NULL;
/* create new FwupdRelease for the XbNode */
- if (!fu_engine_set_release_from_appstream(self,
- request,
- device,
- rel,
- component,
- release,
- &error_loop)) {
- g_warning("failed to set release for component: %s", error_loop->message);
+ fu_release_set_request(release, request);
+ fu_release_set_device(release, device);
+ if (!fu_engine_load_release(self,
+ release,
+ component,
+ rel,
+ install_flags,
+ &error_loop)) {
+ g_debug("failed to set release for component: %s", error_loop->message);
continue;
}
/* fall back to quirk-provided value */
- if (fwupd_release_get_install_duration(rel) == 0)
- fwupd_release_set_install_duration(rel,
+ if (fwupd_release_get_install_duration(FWUPD_RELEASE(release)) == 0) {
+ fwupd_release_set_install_duration(FWUPD_RELEASE(release),
fu_device_get_install_duration(device));
+ }
/* invalid */
- locations = fwupd_release_get_locations(rel);
+ locations = fwupd_release_get_locations(FWUPD_RELEASE(release));
if (locations->len == 0)
continue;
- checksums = fwupd_release_get_checksums(rel);
+ checksums = fu_release_get_checksums(release);
if (checksums->len == 0)
continue;
/* different branch */
- if (g_strcmp0(fwupd_release_get_branch(rel), fu_device_get_branch(device)) != 0) {
+ if (g_strcmp0(fu_release_get_branch(release), fu_device_get_branch(device)) != 0) {
if ((feature_flags & FWUPD_FEATURE_FLAG_SWITCH_BRANCH) == 0) {
g_debug("client does not understand branches, skipping %s:%s",
- fwupd_release_get_branch(rel),
- fwupd_release_get_version(rel));
+ fu_release_get_branch(release),
+ fu_release_get_version(release));
continue;
}
- fwupd_release_add_flag(rel, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH);
+ fu_release_add_flag(release, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH);
}
/* test for upgrade or downgrade */
- vercmp = fu_common_vercmp_full(fwupd_release_get_version(rel),
+ vercmp = fu_common_vercmp_full(fu_release_get_version(release),
fu_device_get_version(device),
fmt);
if (vercmp > 0)
- fwupd_release_add_flag(rel, FWUPD_RELEASE_FLAG_IS_UPGRADE);
+ fu_release_add_flag(release, FWUPD_RELEASE_FLAG_IS_UPGRADE);
else if (vercmp < 0)
- fwupd_release_add_flag(rel, FWUPD_RELEASE_FLAG_IS_DOWNGRADE);
+ fu_release_add_flag(release, FWUPD_RELEASE_FLAG_IS_DOWNGRADE);
/* lower than allowed to downgrade to */
if (fu_device_get_version_lowest(device) != NULL &&
- fu_common_vercmp_full(fwupd_release_get_version(rel),
+ fu_common_vercmp_full(fu_release_get_version(release),
fu_device_get_version_lowest(device),
fmt) < 0) {
- fwupd_release_add_flag(rel, FWUPD_RELEASE_FLAG_BLOCKED_VERSION);
+ fu_release_add_flag(release, FWUPD_RELEASE_FLAG_BLOCKED_VERSION);
}
/* manually blocked */
- if (fu_engine_check_release_is_blocked(self, rel))
- fwupd_release_add_flag(rel, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL);
+ if (fu_engine_check_release_is_blocked(self, release))
+ fu_release_add_flag(release, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL);
/* check if remote is filtering firmware */
- remote_id = fwupd_release_get_remote_id(rel);
+ remote_id = fwupd_release_get_remote_id(FWUPD_RELEASE(release));
if (remote_id != NULL) {
FwupdRemote *remote = fu_engine_get_remote_by_id(self, remote_id, NULL);
if (remote != NULL && fwupd_remote_get_approval_required(remote) &&
- !fu_engine_check_release_is_approved(self, rel)) {
- fwupd_release_add_flag(rel, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL);
+ !fu_engine_check_release_is_approved(self, FWUPD_RELEASE(release))) {
+ fu_release_add_flag(release, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL);
}
}
/* add update message if exists but device doesn't already have one */
- update_message = fwupd_release_get_update_message(rel);
+ update_message = fwupd_release_get_update_message(FWUPD_RELEASE(release));
if (fwupd_device_get_update_message(FWUPD_DEVICE(device)) == NULL &&
update_message != NULL) {
fu_device_set_update_message(device, update_message);
}
- update_image = fwupd_release_get_update_image(rel);
+ update_image = fwupd_release_get_update_image(FWUPD_RELEASE(release));
if (fwupd_device_get_update_image(FWUPD_DEVICE(device)) == NULL &&
update_image != NULL) {
fwupd_device_set_update_image(FWUPD_DEVICE(device), update_image);
}
/* success */
- g_ptr_array_add(releases, g_steal_pointer(&rel));
+ g_ptr_array_add(releases, g_steal_pointer(&release));
}
/* success */
@@ -5238,12 +4748,12 @@ fu_engine_get_releases_for_device(FuEngine *self,
GError **error)
{
GPtrArray *device_guids;
- GPtrArray *releases;
const gchar *version;
g_autoptr(GError) error_all = NULL;
g_autoptr(GError) error_local = NULL;
g_autoptr(GPtrArray) branches = NULL;
g_autoptr(GPtrArray) components = NULL;
+ g_autoptr(GPtrArray) releases = NULL;
g_autoptr(GString) xpath = g_string_new(NULL);
/* get device version */
@@ -5336,7 +4846,7 @@ fu_engine_get_releases_for_device(FuEngine *self,
g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "No releases found");
return NULL;
}
- return releases;
+ return g_steal_pointer(&releases);
}
/**
@@ -6082,22 +5592,22 @@ fu_engine_add_device(FuEngine *self, FuDevice *device)
component = fu_engine_get_component_by_guids(self, device);
if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_LOCKED)) {
if (component != NULL) {
- g_autoptr(XbNode) release = NULL;
- release = xb_node_query_first(component, "releases/release", NULL);
- if (release != NULL) {
- g_autoptr(FwupdRelease) rel = fwupd_release_new();
+ g_autoptr(XbNode) rel = NULL;
+ rel = xb_node_query_first(component, "releases/release", NULL);
+ if (rel != NULL) {
+ g_autoptr(FuRelease) release = fu_release_new();
g_autoptr(GError) error_local = NULL;
- if (!fu_engine_set_release_from_appstream(self,
- NULL,
- device,
- rel,
- component,
- release,
- &error_local)) {
+ fu_release_set_device(release, device);
+ if (!fu_engine_load_release(self,
+ release,
+ component,
+ rel,
+ FWUPD_INSTALL_FLAG_NONE,
+ &error_local)) {
g_warning("failed to set AppStream release: %s",
error_local->message);
} else {
- fu_device_add_release(device, rel);
+ fu_device_add_release(device, FWUPD_RELEASE(release));
}
}
}
diff --git a/src/fu-engine.h b/src/fu-engine.h
index 1839241db..51fa57cb8 100644
--- a/src/fu-engine.h
+++ b/src/fu-engine.h
@@ -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
diff --git a/src/fu-install-task.c b/src/fu-install-task.c
deleted file mode 100644
index 759ff10bb..000000000
--- a/src/fu-install-task.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright (C) 2018 Richard Hughes
- *
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#define G_LOG_DOMAIN "FuInstallTask"
-
-#include "config.h"
-
-#include
-
-#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);
-}
diff --git a/src/fu-install-task.h b/src/fu-install-task.h
deleted file mode 100644
index f99ee29a7..000000000
--- a/src/fu-install-task.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2015 Richard Hughes
- *
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#pragma once
-
-#include
-#include
-
-#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);
diff --git a/src/fu-main.c b/src/fu-main.c
index aac715c48..cacb54e2f 100644
--- a/src/fu-main.c
+++ b/src/fu-main.c
@@ -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;
}
diff --git a/src/fu-release.c b/src/fu-release.c
new file mode 100644
index 000000000..363aa29f8
--- /dev/null
+++ b/src/fu-release.c
@@ -0,0 +1,1067 @@
+/*
+ * Copyright (C) 2018 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuRelease"
+
+#include "config.h"
+
+#include "fu-device-private.h"
+#include "fu-keyring-utils.h"
+#include "fu-release.h"
+
+/**
+ * FuRelease:
+ *
+ * An installable entity that has been loaded and verified for a specific device.
+ *
+ * See also: [class@FwupdRelease]
+ */
+
+struct _FuRelease {
+ FwupdRelease parent_instance;
+ FuEngineRequest *request;
+ FuDevice *device;
+ FwupdRemote *remote;
+ FuConfig *config;
+ GBytes *blob_fw;
+ FwupdReleaseFlags trust_flags;
+ gboolean is_downgrade;
+ gchar *builder_script;
+ gchar *builder_output;
+ GPtrArray *soft_reqs; /* nullable, element-type XbNode */
+ GPtrArray *hard_reqs; /* nullable, element-type XbNode */
+};
+
+G_DEFINE_TYPE(FuRelease, fu_release, FWUPD_TYPE_RELEASE)
+
+/**
+ * fu_release_get_builder_script:
+ * @self: a #FuRelease
+ *
+ * Gets the builder script to use when installing this release.
+ *
+ * Returns: (transfer none) (nullable): filename, e.g. `build.sh`
+ **/
+const gchar *
+fu_release_get_builder_script(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), NULL);
+ return self->builder_script;
+}
+
+/**
+ * fu_release_get_builder_output:
+ * @self: a #FuRelease
+ *
+ * Gets the output filename to use when installing this release.
+ *
+ * Returns: (transfer none) (nullable): filename, e.g. `filename.bin`
+ **/
+const gchar *
+fu_release_get_builder_output(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), NULL);
+ return self->builder_output;
+}
+
+/**
+ * fu_release_set_request:
+ * @self: a #FuRelease
+ * @request: (nullable): a #FuEngineRequest
+ *
+ * Sets the user request which created this operation.
+ **/
+void
+fu_release_set_request(FuRelease *self, FuEngineRequest *request)
+{
+ g_return_if_fail(FU_IS_RELEASE(self));
+ g_set_object(&self->request, request);
+}
+
+/**
+ * fu_release_get_request:
+ * @self: a #FuRelease
+ *
+ * Gets the user request which created this operation.
+ *
+ * Returns: (transfer none) (nullable): request
+ **/
+FuEngineRequest *
+fu_release_get_request(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), NULL);
+ return self->request;
+}
+
+/**
+ * fu_release_set_device:
+ * @self: a #FuRelease
+ * @device: (nullable): a #FuDevice
+ *
+ * Sets the device this release should use when checking requirements.
+ **/
+void
+fu_release_set_device(FuRelease *self, FuDevice *device)
+{
+ g_return_if_fail(FU_IS_RELEASE(self));
+ g_set_object(&self->device, device);
+}
+
+/**
+ * fu_release_get_device:
+ * @self: a #FuRelease
+ *
+ * Gets the device this release was loaded for.
+ *
+ * Returns: (transfer none) (nullable): device
+ **/
+FuDevice *
+fu_release_get_device(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), NULL);
+ return self->device;
+}
+
+/**
+ * fu_release_get_fw_blob:
+ * @self: a #FuRelease
+ *
+ * Gets the firmware payload to use when installing this release.
+ *
+ * Returns: (transfer none) (nullable): data
+ **/
+GBytes *
+fu_release_get_fw_blob(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), NULL);
+ return self->blob_fw;
+}
+
+/**
+ * fu_release_get_soft_reqs:
+ * @self: a #FuRelease
+ *
+ * Gets the additional soft requirements that need to be checked in the engine.
+ *
+ * Returns: (transfer none) (nullable) (element-type XbNode): nodes
+ **/
+GPtrArray *
+fu_release_get_soft_reqs(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), NULL);
+ return self->soft_reqs;
+}
+
+/**
+ * fu_release_get_soft_reqs:
+ * @self: a #FuRelease
+ *
+ * Gets the additional hard requirements that need to be checked in the engine.
+ *
+ * Returns: (transfer none) (nullable) (element-type XbNode): nodes
+ **/
+GPtrArray *
+fu_release_get_hard_reqs(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), NULL);
+ return self->hard_reqs;
+}
+
+/**
+ * fu_release_set_remote:
+ * @self: a #FuRelease
+ * @remote: (nullable): a #FwupdRemote
+ *
+ * Sets the remote this release should use when loading. This is typically set by the engine by
+ *watching the `remote-id` property to be set and then querying the internal cached list of
+ *`FuRemote`s.
+ **/
+void
+fu_release_set_remote(FuRelease *self, FwupdRemote *remote)
+{
+ g_return_if_fail(FU_IS_RELEASE(self));
+ g_set_object(&self->remote, remote);
+}
+
+/**
+ * fu_release_set_config:
+ * @self: a #FuRelease
+ * @config: (nullable): a #FuConfig
+ *
+ * Sets the config to use when loading. The config may be used for things like ordering attributes
+ *like protocol priority.
+ **/
+void
+fu_release_set_config(FuRelease *self, FuConfig *config)
+{
+ g_return_if_fail(FU_IS_RELEASE(self));
+ g_set_object(&self->config, config);
+}
+
+static gchar *
+fu_release_get_localized_xpath(FuRelease *self, const gchar *element)
+{
+ GString *xpath = g_string_new(element);
+ const gchar *locale = NULL;
+
+ /* optional; not set in tests */
+ if (self->request != NULL)
+ locale = fu_engine_request_get_locale(self->request);
+
+ /* prefer the users locale if set */
+ if (locale != NULL) {
+ g_autofree gchar *xpath_locale = NULL;
+ xpath_locale = g_strdup_printf("%s[@xml:lang='%s']|", element, locale);
+ g_string_prepend(xpath, xpath_locale);
+ }
+ return g_string_free(xpath, FALSE);
+}
+
+/* convert hex and decimal versions to dotted style */
+static gchar *
+fu_release_get_release_version(FuRelease *self, const gchar *version, GError **error)
+{
+ FwupdVersionFormat fmt = fu_device_get_version_format(self->device);
+ guint64 ver_uint32;
+
+ /* already dotted notation */
+ if (g_strstr_len(version, -1, ".") != NULL)
+ return g_strdup(version);
+
+ /* don't touch my version! */
+ if (fmt == FWUPD_VERSION_FORMAT_PLAIN)
+ return g_strdup(version);
+
+ /* parse as integer */
+ ver_uint32 = fu_common_strtoull(version);
+ if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN || ver_uint32 == 0 || ver_uint32 > G_MAXUINT32)
+ return g_strdup(version);
+
+ /* convert to dotted decimal */
+ return fu_common_version_from_uint32((guint32)ver_uint32, fmt);
+}
+
+static gboolean
+fu_release_load_artifact(FuRelease *self, XbNode *artifact, GError **error)
+{
+ const gchar *filename;
+ guint64 size;
+ g_autoptr(GPtrArray) locations = NULL;
+ g_autoptr(GPtrArray) checksums = NULL;
+
+ /* filename */
+ filename = xb_node_query_text(artifact, "filename", NULL);
+ if (filename != NULL)
+ fwupd_release_set_filename(FWUPD_RELEASE(self), filename);
+
+ /* location */
+ locations = xb_node_query(artifact, "location", 0, NULL);
+ if (locations != NULL) {
+ for (guint i = 0; i < locations->len; i++) {
+ XbNode *n = g_ptr_array_index(locations, i);
+ g_autofree gchar *scheme = NULL;
+
+ /* check the scheme is allowed */
+ scheme = fu_common_uri_get_scheme(xb_node_get_text(n));
+ if (scheme != NULL) {
+ guint prio = fu_config_get_uri_scheme_prio(self->config, scheme);
+ if (prio == G_MAXUINT)
+ continue;
+ }
+
+ /* build the complete URI */
+ if (self->remote != NULL) {
+ g_autofree gchar *uri = NULL;
+ uri = fwupd_remote_build_firmware_uri(self->remote,
+ xb_node_get_text(n),
+ NULL);
+ if (uri != NULL) {
+ fwupd_release_add_location(FWUPD_RELEASE(self), uri);
+ continue;
+ }
+ }
+ fwupd_release_add_location(FWUPD_RELEASE(self), xb_node_get_text(n));
+ }
+ }
+
+ /* checksum */
+ checksums = xb_node_query(artifact, "checksum", 0, NULL);
+ if (checksums != NULL) {
+ for (guint i = 0; i < checksums->len; i++) {
+ XbNode *n = g_ptr_array_index(checksums, i);
+ fwupd_release_add_checksum(FWUPD_RELEASE(self), xb_node_get_text(n));
+ }
+ }
+
+ /* size */
+ size = xb_node_query_text_as_uint(artifact, "size[@type='installed']", NULL);
+ if (size != G_MAXUINT64)
+ fwupd_release_set_size(FWUPD_RELEASE(self), size);
+
+ /* success */
+ return TRUE;
+}
+
+static gint
+fu_release_scheme_compare_cb(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ FuRelease *self = FU_RELEASE(user_data);
+ const gchar *location1 = *((const gchar **)a);
+ const gchar *location2 = *((const gchar **)b);
+ g_autofree gchar *scheme1 = fu_common_uri_get_scheme(location1);
+ g_autofree gchar *scheme2 = fu_common_uri_get_scheme(location2);
+ guint prio1 = fu_config_get_uri_scheme_prio(self->config, scheme1);
+ guint prio2 = fu_config_get_uri_scheme_prio(self->config, scheme2);
+ if (prio1 < prio2)
+ return -1;
+ if (prio1 > prio2)
+ return 1;
+ return 0;
+}
+
+static gboolean
+fu_release_check_requirements_version_check(FuRelease *self, GError **error)
+{
+ if (self->hard_reqs != NULL) {
+ for (guint i = 0; i < self->hard_reqs->len; i++) {
+ XbNode *req = g_ptr_array_index(self->hard_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;
+}
+
+static gchar *
+fu_release_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_release_check_verfmt(FuRelease *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_release_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_release_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;
+}
+
+/* these can all be done without the daemon */
+static gboolean
+fu_release_check_requirements(FuRelease *self,
+ XbNode *component,
+ XbNode *rel,
+ FwupdInstallFlags install_flags,
+ GError **error)
+{
+ const gchar *branch_new;
+ const gchar *branch_old;
+ const gchar *protocol;
+ const gchar *version;
+ const gchar *version_lowest;
+ gboolean matches_guid = FALSE;
+ gint vercmp;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) provides = NULL;
+ g_autoptr(GPtrArray) verfmts = NULL;
+
+ /* does this component provide a GUID the device has */
+ provides = xb_node_query(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_release_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(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) &&
+ (install_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(component, "branch", NULL);
+ branch_old = fu_device_get_branch(self->device);
+ if ((install_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 ((install_flags & FWUPD_INSTALL_FLAG_OFFLINE) == 0 &&
+ (install_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;
+ }
+
+ /* check the version formats match if set in the release */
+ if ((install_flags & FWUPD_INSTALL_FLAG_FORCE) == 0 &&
+ (install_flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) == 0) {
+ verfmts =
+ xb_node_query(component, "custom/value[@key='LVFS::VersionFormat']", 0, NULL);
+ if (verfmts != NULL) {
+ if (!fu_release_check_verfmt(self, verfmts, install_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,
+ fu_release_get_version(self),
+ fu_device_get_version_format(self->device)) > 0 &&
+ (install_flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Specified firmware is older than the minimum "
+ "required version '%s < %s'",
+ version,
+ version_lowest);
+ return FALSE;
+ }
+
+ /* is this a downgrade or re-install */
+ vercmp = fu_common_vercmp_full(version,
+ fu_release_get_version(self),
+ 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 && (install_flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_VERSION_SAME,
+ "Specified firmware is already installed '%s'",
+ fu_release_get_version(self));
+ return FALSE;
+ }
+ self->is_downgrade = vercmp > 0;
+ if (self->is_downgrade && (install_flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0 &&
+ (install_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'",
+ fu_release_get_version(self),
+ version);
+ return FALSE;
+ }
+
+ /* verify */
+ if (!fu_keyring_get_release_flags(rel, &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_release_load:
+ * @self: a #FuRelease
+ * @component: (not nullable): a #XbNode
+ * @rel_optional: (nullable): a #XbNode
+ * @install_flags: a #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_FORCE
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads then checks any requirements of this release. 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 release was loaded and the requirements passed
+ **/
+gboolean
+fu_release_load(FuRelease *self,
+ XbNode *component,
+ XbNode *rel_optional,
+ FwupdInstallFlags install_flags,
+ GError **error)
+{
+ const gchar *tmp;
+ guint64 tmp64;
+ GBytes *blob_fw_tmp;
+ g_autofree gchar *name_xpath = NULL;
+ g_autofree gchar *namevs_xpath = NULL;
+ g_autofree gchar *summary_xpath = NULL;
+ g_autofree gchar *description_xpath = NULL;
+ g_autoptr(GPtrArray) cats = NULL;
+ g_autoptr(GPtrArray) tags = NULL;
+ g_autoptr(GPtrArray) issues = NULL;
+ g_autoptr(XbNode) artifact = NULL;
+ g_autoptr(XbNode) description = NULL;
+ g_autoptr(XbNode) rel = NULL;
+ g_autoptr(GError) error_soft = NULL;
+ g_autoptr(GError) error_hard = NULL;
+
+ g_return_val_if_fail(FU_IS_RELEASE(self), FALSE);
+ g_return_val_if_fail(XB_IS_NODE(component), FALSE);
+ g_return_val_if_fail(rel_optional == NULL || XB_IS_NODE(rel_optional), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail(fwupd_release_get_appstream_id(FWUPD_RELEASE(self)) == NULL, FALSE);
+
+ /* set from the component */
+ tmp = xb_node_query_text(component, "id", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_appstream_id(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "url[@type='homepage']", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_homepage(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "project_license", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_license(FWUPD_RELEASE(self), tmp);
+ name_xpath = fu_release_get_localized_xpath(self, "name");
+ tmp = xb_node_query_text(component, name_xpath, NULL);
+ if (tmp != NULL)
+ fwupd_release_set_name(FWUPD_RELEASE(self), tmp);
+ summary_xpath = fu_release_get_localized_xpath(self, "summary");
+ tmp = xb_node_query_text(component, summary_xpath, NULL);
+ if (tmp != NULL)
+ fwupd_release_set_summary(FWUPD_RELEASE(self), tmp);
+ namevs_xpath = fu_release_get_localized_xpath(self, "name_variant_suffix");
+ tmp = xb_node_query_text(component, namevs_xpath, NULL);
+ if (tmp != NULL)
+ fwupd_release_set_name_variant_suffix(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "branch", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_branch(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "developer_name", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_vendor(FWUPD_RELEASE(self), tmp);
+
+ /* use default release */
+ if (rel_optional == NULL) {
+ g_autoptr(GError) error_local = NULL;
+#if LIBXMLB_CHECK_VERSION(0, 2, 0)
+ g_autoptr(XbQuery) query = NULL;
+ query = xb_query_new_full(xb_node_get_silo(component),
+ "releases/release",
+ XB_QUERY_FLAG_FORCE_NODE_CACHE,
+ error);
+ if (query == NULL)
+ return FALSE;
+ rel = xb_node_query_first_full(component, query, &error_local);
+#else
+ rel = xb_node_query_first(component, "releases/release", &error_local);
+#endif
+ if (rel == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "failed to get default release: %s",
+ error_local->message);
+ return FALSE;
+ }
+ } else {
+ rel = g_object_ref(rel_optional);
+ }
+
+ /* the version is fixed up with the device format */
+ tmp = xb_node_get_attr(rel, "version");
+ if (tmp == NULL) {
+ g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "version unset");
+ return FALSE;
+ }
+ if (self->device != NULL) {
+ g_autofree gchar *version_rel = NULL;
+ version_rel = fu_release_get_release_version(self, tmp, error);
+ if (version_rel == NULL)
+ return FALSE;
+ fwupd_release_set_version(FWUPD_RELEASE(self), version_rel);
+ } else {
+ fwupd_release_set_version(FWUPD_RELEASE(self), tmp);
+ }
+
+ /* optional release ID -- currently a integer but maybe namespaced in the future */
+ fwupd_release_set_id(FWUPD_RELEASE(self), xb_node_get_attr(rel, "id"));
+
+ /* find the remote */
+ tmp = xb_node_query_text(component, "../custom/value[@key='fwupd::RemoteId']", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_remote_id(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "../custom/value[@key='LVFS::Distributor']", NULL);
+ if (g_strcmp0(tmp, "community") == 0)
+ fwupd_release_add_flag(FWUPD_RELEASE(self), FWUPD_RELEASE_FLAG_IS_COMMUNITY);
+
+ /* this is the more modern way to do this */
+ artifact = xb_node_query_first(rel, "artifacts/artifact", NULL);
+ if (artifact != NULL) {
+ if (!fu_release_load_artifact(self, artifact, error))
+ return FALSE;
+ }
+ description_xpath = fu_release_get_localized_xpath(self, "description");
+ description = xb_node_query_first(rel, description_xpath, NULL);
+ if (description != NULL) {
+ g_autofree gchar *xml = NULL;
+ g_autoptr(GString) str = NULL;
+ xml = xb_node_export(description, XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, NULL);
+ str = g_string_new(xml);
+ if (self->device != NULL && self->request != NULL &&
+ fu_device_has_flag(self->device, FWUPD_DEVICE_FLAG_AFFECTS_FDE) &&
+ !fu_engine_request_has_feature_flag(self->request,
+ FWUPD_FEATURE_FLAG_FDE_WARNING)) {
+ g_string_prepend(
+ str,
+ "Some of the platform secrets may be invalidated when "
+ "updating this firmware. Please ensure you have the volume "
+ "recovery key before continuing.
");
+ }
+ if (fwupd_release_has_flag(FWUPD_RELEASE(self), FWUPD_RELEASE_FLAG_IS_COMMUNITY) &&
+ self->request != NULL &&
+ !fu_engine_request_has_feature_flag(self->request,
+ FWUPD_FEATURE_FLAG_COMMUNITY_TEXT)) {
+ g_string_prepend(
+ str,
+ "This firmware is provided by LVFS community "
+ "members and is not provided (or supported) by the original "
+ "hardware vendor. "
+ "Installing this update may also void any device warranty.
");
+ }
+ if (str->len > 0)
+ fwupd_release_set_description(FWUPD_RELEASE(self), str->str);
+ }
+ if (artifact == NULL) {
+ tmp = xb_node_query_text(rel, "location", NULL);
+ if (tmp != NULL) {
+ g_autofree gchar *uri = NULL;
+ if (self->remote != NULL)
+ uri = fwupd_remote_build_firmware_uri(self->remote, tmp, NULL);
+ if (uri == NULL)
+ uri = g_strdup(tmp);
+ fwupd_release_add_location(FWUPD_RELEASE(self), uri);
+ }
+ }
+ if (fwupd_release_get_locations(FWUPD_RELEASE(self))->len == 0 && self->remote != NULL &&
+ fwupd_remote_get_kind(self->remote) == FWUPD_REMOTE_KIND_DIRECTORY) {
+ tmp = xb_node_query_text(component,
+ "../custom/value[@key='fwupd::FilenameCache']",
+ NULL);
+ if (tmp != NULL) {
+ g_autofree gchar *uri = g_strdup_printf("file://%s", tmp);
+ fwupd_release_add_location(FWUPD_RELEASE(self), uri);
+ }
+ }
+ if (artifact == NULL) {
+ tmp = xb_node_query_text(rel, "checksum[@target='content']", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_filename(FWUPD_RELEASE(self), tmp);
+ }
+ tmp = xb_node_query_text(rel, "url[@type='details']", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_details_url(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(rel, "url[@type='source']", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_source_url(FWUPD_RELEASE(self), tmp);
+ if (artifact == NULL) {
+ g_autoptr(GPtrArray) checksums = NULL;
+ checksums = xb_node_query(rel, "checksum[@target='container']", 0, NULL);
+ if (checksums != NULL) {
+ for (guint i = 0; i < checksums->len; i++) {
+ XbNode *n = g_ptr_array_index(checksums, i);
+ if (xb_node_get_text(n) == NULL)
+ continue;
+ fwupd_release_add_checksum(FWUPD_RELEASE(self),
+ xb_node_get_text(n));
+ }
+ }
+ }
+ if (artifact == NULL) {
+ tmp64 = xb_node_query_text_as_uint(rel, "size[@type='installed']", NULL);
+ if (tmp64 != G_MAXUINT64)
+ fwupd_release_set_size(FWUPD_RELEASE(self), tmp64);
+ }
+ if (fwupd_release_get_size(FWUPD_RELEASE(self)) == 0) {
+ GBytes *sz = xb_node_get_data(rel, "fwupd::ReleaseSize");
+ if (sz != NULL) {
+ const guint64 *sizeptr = g_bytes_get_data(sz, NULL);
+ fwupd_release_set_size(FWUPD_RELEASE(self), *sizeptr);
+ }
+ }
+ tmp = xb_node_get_attr(rel, "urgency");
+ if (tmp != NULL)
+ fwupd_release_set_urgency(FWUPD_RELEASE(self),
+ fwupd_release_urgency_from_string(tmp));
+ tmp64 = xb_node_get_attr_as_uint(rel, "install_duration");
+ if (tmp64 != G_MAXUINT64)
+ fwupd_release_set_install_duration(FWUPD_RELEASE(self), tmp64);
+ tmp64 = xb_node_get_attr_as_uint(rel, "timestamp");
+ if (tmp64 != G_MAXUINT64)
+ fwupd_release_set_created(FWUPD_RELEASE(self), tmp64);
+ cats = xb_node_query(component, "categories/category", 0, NULL);
+ if (cats != NULL) {
+ for (guint i = 0; i < cats->len; i++) {
+ XbNode *n = g_ptr_array_index(cats, i);
+ fwupd_release_add_category(FWUPD_RELEASE(self), xb_node_get_text(n));
+ }
+ }
+ tags = xb_node_query(component, "tags/tag[@namespace=$'lvfs']", 0, NULL);
+ if (tags != NULL) {
+ for (guint i = 0; i < tags->len; i++) {
+ XbNode *tag = g_ptr_array_index(tags, i);
+ fwupd_release_add_tag(FWUPD_RELEASE(self), xb_node_get_text(tag));
+ }
+ }
+ issues = xb_node_query(component, "issues/issue", 0, NULL);
+ if (issues != NULL) {
+ for (guint i = 0; i < issues->len; i++) {
+ XbNode *n = g_ptr_array_index(issues, i);
+ fwupd_release_add_issue(FWUPD_RELEASE(self), xb_node_get_text(n));
+ }
+ }
+ tmp = xb_node_query_text(component, "screenshots/screenshot/caption", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_detach_caption(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "screenshots/screenshot/image", NULL);
+ if (tmp != NULL) {
+ if (self->remote != NULL) {
+ g_autofree gchar *img = NULL;
+ img = fwupd_remote_build_firmware_uri(self->remote, tmp, error);
+ if (img == NULL)
+ return FALSE;
+ fwupd_release_set_detach_image(FWUPD_RELEASE(self), img);
+ } else {
+ fwupd_release_set_detach_image(FWUPD_RELEASE(self), tmp);
+ }
+ }
+ tmp = xb_node_query_text(component, "custom/value[@key='LVFS::UpdateProtocol']", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_protocol(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "custom/value[@key='LVFS::UpdateMessage']", NULL);
+ if (tmp != NULL)
+ fwupd_release_set_update_message(FWUPD_RELEASE(self), tmp);
+ tmp = xb_node_query_text(component, "custom/value[@key='LVFS::UpdateImage']", NULL);
+ if (tmp != NULL) {
+ if (self->remote != NULL) {
+ g_autofree gchar *img = NULL;
+ img = fwupd_remote_build_firmware_uri(self->remote, tmp, error);
+ if (img == NULL)
+ return FALSE;
+ fwupd_release_set_update_image(FWUPD_RELEASE(self), img);
+ } else {
+ fwupd_release_set_update_image(FWUPD_RELEASE(self), tmp);
+ }
+ }
+
+ /* hard and soft requirements */
+ self->hard_reqs = xb_node_query(component, "requires/*", 0, &error_hard);
+ if (self->hard_reqs == NULL) {
+ if (!g_error_matches(error_hard, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
+ !g_error_matches(error_hard, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
+ g_propagate_error(error, g_steal_pointer(&error_hard));
+ return FALSE;
+ }
+ }
+ self->soft_reqs = xb_node_query(component, "suggests/*|recommends/*", 0, &error_soft);
+ if (self->soft_reqs == NULL) {
+ if (!g_error_matches(error_soft, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
+ !g_error_matches(error_soft, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
+ g_propagate_error(error, g_steal_pointer(&error_soft));
+ return FALSE;
+ }
+ }
+
+ /* get per-release firmware blob */
+ blob_fw_tmp = xb_node_get_data(rel, "fwupd::FirmwareBlob");
+ if (blob_fw_tmp != NULL)
+ self->blob_fw = g_bytes_ref(blob_fw_tmp);
+
+ /* to build the firmware */
+ tmp = g_object_get_data(G_OBJECT(component), "fwupd::BuilderScript");
+ if (tmp != NULL) {
+ self->builder_script = g_strdup(tmp);
+ tmp = g_object_get_data(G_OBJECT(component), "fwupd::BuilderOutput");
+ if (tmp == NULL)
+ tmp = "firmware.bin";
+ self->builder_output = g_strdup(tmp);
+ }
+
+ /* sort the locations by scheme */
+ if (self->config != NULL) {
+ g_ptr_array_sort_with_data(fwupd_release_get_locations(FWUPD_RELEASE(self)),
+ fu_release_scheme_compare_cb,
+ self);
+ }
+
+ /* check requirements for device */
+ if (self->device != NULL && self->request != NULL &&
+ fu_engine_request_get_kind(self->request) == FU_ENGINE_REQUEST_KIND_ACTIVE) {
+ if (!fu_release_check_requirements(self, component, rel, install_flags, error))
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_release_get_trust_flags:
+ * @self: a #FuRelease
+ *
+ * Gets the trust flags for this task.
+ *
+ * NOTE: This is only set after fu_release_load() has been called successfully, and
+ * is only valid when a request has been set.
+ *
+ * Returns: the #FwupdReleaseFlags, e.g. #FWUPD_TRUST_FLAG_PAYLOAD
+ **/
+FwupdReleaseFlags
+fu_release_get_trust_flags(FuRelease *self)
+{
+ g_return_val_if_fail(FU_IS_RELEASE(self), FALSE);
+ return self->trust_flags;
+}
+
+/**
+ * fu_release_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_release_get_action_id(FuRelease *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";
+}
+
+/**
+ * fu_release_compare:
+ * @release1: first task to compare.
+ * @release2: second task to compare.
+ *
+ * Compares two install tasks.
+ *
+ * Returns: 1, 0 or -1 if @release1 is greater, equal, or less than @release2, respectively.
+ **/
+gint
+fu_release_compare(FuRelease *release1, FuRelease *release2)
+{
+ FuDevice *device1 = fu_release_get_device(release1);
+ FuDevice *device2 = fu_release_get_device(release2);
+ 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;
+}
+
+static void
+fu_release_init(FuRelease *self)
+{
+ self->trust_flags = FWUPD_TRUST_FLAG_NONE;
+}
+
+static void
+fu_release_finalize(GObject *obj)
+{
+ FuRelease *self = FU_RELEASE(obj);
+
+ g_free(self->builder_script);
+ g_free(self->builder_output);
+ if (self->request != NULL)
+ g_object_unref(self->request);
+ if (self->device != NULL)
+ g_object_unref(self->device);
+ if (self->remote != NULL)
+ g_object_unref(self->remote);
+ if (self->config != NULL)
+ g_object_unref(self->config);
+ if (self->blob_fw != NULL)
+ g_bytes_unref(self->blob_fw);
+ if (self->soft_reqs != NULL)
+ g_ptr_array_unref(self->soft_reqs);
+ if (self->hard_reqs != NULL)
+ g_ptr_array_unref(self->hard_reqs);
+
+ G_OBJECT_CLASS(fu_release_parent_class)->finalize(obj);
+}
+
+static void
+fu_release_class_init(FuReleaseClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fu_release_finalize;
+}
+
+FuRelease *
+fu_release_new(void)
+{
+ FuRelease *self;
+ self = g_object_new(FU_TYPE_RELEASE, NULL);
+ return FU_RELEASE(self);
+}
diff --git a/src/fu-release.h b/src/fu-release.h
new file mode 100644
index 000000000..b95f68629
--- /dev/null
+++ b/src/fu-release.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+#include
+
+#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);
diff --git a/src/fu-self-test.c b/src/fu-self-test.c
index 8c5a001c3..bd0f7fc61 100644
--- a/src/fu-self-test.c
+++ b/src/fu-self-test.c
@@ -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 = ""
" "
" not.going.to.exist"
" "
+ " "
+ " "
+ " "
"";
/* 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 = ""
" "
" not.going.to.exist"
" "
+ " "
+ " "
+ " "
"";
/* 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 = ""
" "
" detach-action"
" "
+ " "
+ " "
+ " "
"";
/* 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 = ""
" "
" hello-dave"
" "
+ " "
+ " "
+ " "
"";
/* 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 = ""
" "
" detach-action"
" "
+ " "
+ " "
+ " "
"";
/* 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 =
+ ""
+ " "
+ " 12345678-1234-1234-1234-123456789012"
+ " "
+ " "
+ " "
+ " "
+ " "
+ "";
+
+ /* 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 = ""
" "
" "
" "
+ " "
+ " "
+ " "
"";
/* 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)
" "
" org.test.dummy"
" "
+ " "
+ " "
+ " "
"";
/* 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);
diff --git a/src/fu-tool.c b/src/fu-tool.c
index 3f3947335..0cdef9091 100644
--- a/src/fu-tool.c
+++ b/src/fu-tool.c
@@ -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);
diff --git a/src/meson.build b/src/meson.build
index 190e3e961..9ef75d93a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -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',