mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-08 00:57:45 +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,
|
fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req,
|
||||||
FuDevice *device, GError **error)
|
FuDevice *device, GError **error)
|
||||||
{
|
{
|
||||||
|
guint64 depth;
|
||||||
|
g_autoptr(FuDevice) device_actual = g_object_ref (device);
|
||||||
g_autoptr(GError) error_local = NULL;
|
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 */
|
/* old firmware version */
|
||||||
if (xb_node_get_text (req) == NULL) {
|
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 (!fu_engine_require_vercmp (req, version, &error_local)) {
|
||||||
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@ -1105,7 +1125,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req,
|
|||||||
|
|
||||||
/* bootloader version */
|
/* bootloader version */
|
||||||
if (g_strcmp0 (xb_node_get_text (req), "bootloader") == 0) {
|
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 (!fu_engine_require_vercmp (req, version, &error_local)) {
|
||||||
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@ -1127,7 +1147,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req,
|
|||||||
|
|
||||||
/* vendor ID */
|
/* vendor ID */
|
||||||
if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0) {
|
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 (!fu_engine_require_vercmp (req, version, &error_local)) {
|
||||||
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@ -1149,29 +1169,44 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req,
|
|||||||
|
|
||||||
/* child version */
|
/* child version */
|
||||||
if (g_strcmp0 (xb_node_get_text (req), "not-child") == 0)
|
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 */
|
/* another device */
|
||||||
if (fwupd_guid_is_valid (xb_node_get_text (req))) {
|
if (fwupd_guid_is_valid (xb_node_get_text (req))) {
|
||||||
const gchar *guid = xb_node_get_text (req);
|
const gchar *guid = xb_node_get_text (req);
|
||||||
const gchar *version;
|
const gchar *version;
|
||||||
g_autoptr(FuDevice) device2 = NULL;
|
|
||||||
|
|
||||||
/* find if the other device exists */
|
/* find if the other device exists */
|
||||||
device2 = fu_device_list_get_by_guid (self->device_list, guid, error);
|
if (depth == G_MAXUINT64) {
|
||||||
if (device2 == NULL)
|
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;
|
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 */
|
/* get the version of the other device */
|
||||||
version = fu_device_get_version (device2);
|
version = fu_device_get_version (device_actual);
|
||||||
if (version != NULL &&
|
if (version != NULL &&
|
||||||
|
xb_node_get_attr (req, "compare") != NULL &&
|
||||||
!fu_engine_require_vercmp (req, version, &error_local)) {
|
!fu_engine_require_vercmp (req, version, &error_local)) {
|
||||||
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
FWUPD_ERROR_INVALID_FILE,
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
"Not compatible with %s version %s, requires >= %s",
|
"Not compatible with %s version %s, requires >= %s",
|
||||||
fu_device_get_name (device2),
|
fu_device_get_name (device_actual),
|
||||||
version,
|
version,
|
||||||
xb_node_get_attr (req, "version"));
|
xb_node_get_attr (req, "version"));
|
||||||
} else {
|
} else {
|
||||||
@ -1179,7 +1214,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req,
|
|||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
FWUPD_ERROR_INVALID_FILE,
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
"Not compatible with %s: %s",
|
"Not compatible with %s: %s",
|
||||||
fu_device_get_name (device2),
|
fu_device_get_name (device_actual),
|
||||||
error_local->message);
|
error_local->message);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -566,6 +566,69 @@ fu_engine_requirements_other_device_func (void)
|
|||||||
g_assert (ret);
|
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
|
static void
|
||||||
fu_engine_device_priority_func (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{downgrade}", fu_engine_downgrade_func);
|
||||||
g_test_add_func ("/fwupd/engine{requirements-success}", fu_engine_requirements_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-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}", 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-not-child-fail}", fu_engine_requirements_child_fail_func);
|
||||||
g_test_add_func ("/fwupd/engine{requirements-unsupported}", fu_engine_requirements_unsupported_func);
|
g_test_add_func ("/fwupd/engine{requirements-unsupported}", fu_engine_requirements_unsupported_func);
|
||||||
|
Loading…
Reference in New Issue
Block a user