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',