mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-04 01:20:25 +00:00
Add support for matching <firmware> requirements on device parents
For composite devices you might want to restrict the child device in respect to the parent, for instance requiring the parent to have greater than a specific firmware version number. The other useful thing to use this for is checking if the parent has a specific GUID (of any version) which allows us to match against the common VID&PID instance IDs. This would allow us to restrict a generic child device update to a specific OEM vendor parent. This is specified as <firmware depth="1" ...> to match the parent device and <firmware depth="2" ...> to match the grandparent device.
This commit is contained in:
parent
e2b8a2797e
commit
f7006d2baa
@ -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;
|
||||
|
@ -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 =
|
||||
"<component>"
|
||||
" <requires>"
|
||||
" <firmware depth=\"1\" compare=\"eq\" version=\"1.2.3\"/>"
|
||||
" <firmware depth=\"1\">12345678-1234-1234-1234-123456789012</firmware>"
|
||||
" </requires>"
|
||||
" <provides>"
|
||||
" <firmware type=\"flashed\">1ff60ab2-3905-06a1-b476-0371f00c9e9b</firmware>"
|
||||
" </provides>"
|
||||
" <releases>"
|
||||
" <release version=\"4.5.7\">"
|
||||
" <checksum type=\"sha1\" filename=\"bios.bin\" target=\"content\"/>"
|
||||
" </release>"
|
||||
" </releases>"
|
||||
"</component>";
|
||||
|
||||
/* 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);
|
||||
|
Loading…
Reference in New Issue
Block a user