diff --git a/src/fu-engine.c b/src/fu-engine.c index 1c348010d..a087354a1 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1079,11 +1079,31 @@ static gboolean fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, FuDevice *device, GError **error) { + guint64 depth; + g_autoptr(FuDevice) device_actual = g_object_ref (device); g_autoptr(GError) error_local = NULL; + /* look at the parent device */ + depth = xb_node_get_attr_as_uint (req, "depth"); + if (depth != G_MAXUINT64) { + for (guint64 i = 0; i < depth; i++) { + FuDevice *device_tmp = fu_device_get_parent (device_actual); + if (device_actual == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No parent device for %s " + "(%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ")", + fu_device_get_name (device_actual), i, depth); + return FALSE; + } + g_set_object (&device_actual, device_tmp); + } + } + /* old firmware version */ if (xb_node_get_text (req) == NULL) { - const gchar *version = fu_device_get_version (device); + const gchar *version = fu_device_get_version (device_actual); if (!fu_engine_require_vercmp (req, version, &error_local)) { if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, @@ -1105,7 +1125,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, /* bootloader version */ if (g_strcmp0 (xb_node_get_text (req), "bootloader") == 0) { - const gchar *version = fu_device_get_version_bootloader (device); + const gchar *version = fu_device_get_version_bootloader (device_actual); if (!fu_engine_require_vercmp (req, version, &error_local)) { if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, @@ -1127,7 +1147,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, /* vendor ID */ if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0) { - const gchar *version = fu_device_get_vendor_id (device); + const gchar *version = fu_device_get_vendor_id (device_actual); if (!fu_engine_require_vercmp (req, version, &error_local)) { if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, @@ -1149,29 +1169,44 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, /* child version */ if (g_strcmp0 (xb_node_get_text (req), "not-child") == 0) - return fu_engine_check_requirement_not_child (self, req, device, error); + return fu_engine_check_requirement_not_child (self, req, device_actual, error); /* another device */ if (fwupd_guid_is_valid (xb_node_get_text (req))) { const gchar *guid = xb_node_get_text (req); const gchar *version; - g_autoptr(FuDevice) device2 = NULL; /* find if the other device exists */ - device2 = fu_device_list_get_by_guid (self->device_list, guid, error); - if (device2 == NULL) - return FALSE; + if (depth == G_MAXUINT64) { + g_autoptr(FuDevice) device_tmp = NULL; + device_tmp = fu_device_list_get_by_guid (self->device_list, guid, error); + if (device_tmp == NULL) + return FALSE; + g_set_object (&device_actual, device_tmp); + + /* verify the parent device has the GUID */ + } else { + if (!fu_device_has_guid (device_actual, guid)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No GUID of %s on parent device %s", + guid, fu_device_get_name (device_actual)); + return FALSE; + } + } /* get the version of the other device */ - version = fu_device_get_version (device2); + version = fu_device_get_version (device_actual); if (version != NULL && + xb_node_get_attr (req, "compare") != NULL && !fu_engine_require_vercmp (req, version, &error_local)) { if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with %s version %s, requires >= %s", - fu_device_get_name (device2), + fu_device_get_name (device_actual), version, xb_node_get_attr (req, "version")); } else { @@ -1179,7 +1214,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with %s: %s", - fu_device_get_name (device2), + fu_device_get_name (device_actual), error_local->message); } return FALSE; diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 0079017a7..26a748621 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -566,6 +566,69 @@ fu_engine_requirements_other_device_func (void) g_assert (ret); } +static void +fu_engine_requirements_parent_device_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device1 = fu_device_new (); + g_autoptr(FuDevice) device2 = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + const gchar *xml = + "" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " 1ff60ab2-3905-06a1-b476-0371f00c9e9b" + " " + " " + " " + " " + " " + " " + ""; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* set up child device */ + fu_device_set_id (device2, "child"); + fu_device_set_name (device2, "child"); + fu_device_set_version (device2, "4.5.6", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_guid (device2, "1ff60ab2-3905-06a1-b476-0371f00c9e9b"); + + /* set up a parent device */ + fu_device_set_id (device1, "parent"); + fu_device_set_name (device1, "parent"); + fu_device_set_version (device1, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_guid (device1, "12345678-1234-1234-1234-123456789012"); + fu_device_add_child (device1, device2); + fu_engine_add_device (engine, device1); + + /* import firmware metainfo */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this passes */ + task = fu_install_task_new (device2, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert (ret); +} + static void fu_engine_device_priority_func (void) { @@ -4168,6 +4231,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/engine{downgrade}", fu_engine_downgrade_func); g_test_add_func ("/fwupd/engine{requirements-success}", fu_engine_requirements_func); g_test_add_func ("/fwupd/engine{requirements-missing}", fu_engine_requirements_missing_func); + g_test_add_func ("/fwupd/engine{requirements-parent-device}", fu_engine_requirements_parent_device_func); g_test_add_func ("/fwupd/engine{requirements-not-child}", fu_engine_requirements_child_func); g_test_add_func ("/fwupd/engine{requirements-not-child-fail}", fu_engine_requirements_child_fail_func); g_test_add_func ("/fwupd/engine{requirements-unsupported}", fu_engine_requirements_unsupported_func);