From be78d0f0ce48d3283ee4f15ad8dc18838a3fd25d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:22:27 +0100 Subject: [PATCH 001/254] trivial: Remove unused header --- src/fu-device.c | 1 - src/fu-plugin.c | 1 - src/fu-udev-device.c | 1 - 3 files changed, 3 deletions(-) diff --git a/src/fu-device.c b/src/fu-device.c index 1be6c0c35..bb427fba8 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -9,7 +9,6 @@ #include "config.h" #include -#include #include #include diff --git a/src/fu-plugin.c b/src/fu-plugin.c index a9598d87e..83bd8c446 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index b3ab95752..db726bb7d 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -8,7 +8,6 @@ #include "config.h" -#include #include #include "fu-udev-device-private.h" From bcf875ff3b7756345ab832dc3eae62e06845e72f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Sep 2018 21:19:31 +0100 Subject: [PATCH 002/254] trivial: Don't use AppStream-glib in libfwupd It's only used in one place, and that's for checking against very old versions of the running daemon. --- libfwupd/fwupd-self-test.c | 5 ++--- libfwupd/meson.build | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libfwupd/fwupd-self-test.c b/libfwupd/fwupd-self-test.c index 3489434a2..c0ee284c0 100644 --- a/libfwupd/fwupd-self-test.c +++ b/libfwupd/fwupd-self-test.c @@ -8,7 +8,6 @@ #include #include -#include #include "fwupd-client.h" #include "fwupd-common.h" @@ -287,7 +286,7 @@ fwupd_client_devices_func (void) g_test_skip ("no enabled fwupd daemon"); return; } - if (as_utils_vercmp (fwupd_client_get_daemon_version (client), "1.0.0") < 0) { + if (!g_str_has_prefix (fwupd_client_get_daemon_version (client), "1.")) { g_test_skip ("running fwupd is too old"); return; } @@ -336,7 +335,7 @@ fwupd_client_remotes_func (void) g_test_skip ("no enabled fwupd daemon"); return; } - if (as_utils_vercmp (fwupd_client_get_daemon_version (client), "1.0.0") < 0) { + if (!g_str_has_prefix (fwupd_client_get_daemon_version (client), "1.")) { g_test_skip ("running fwupd is too old"); return; } diff --git a/libfwupd/meson.build b/libfwupd/meson.build index d16bbb776..ff0bcfcac 100644 --- a/libfwupd/meson.build +++ b/libfwupd/meson.build @@ -154,7 +154,6 @@ if get_option('tests') include_directories('..'), ], dependencies : [ - appstream_glib, gio, soup, ], From d3d2c2c39fd3fd54ee7550fdc6a4cd87874b14b6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:01:05 +0100 Subject: [PATCH 003/254] Don't use AppStream-glib for the GUID helpers Long term we want to wean ourselves away from libappstream-glib. --- plugins/dell/fu-plugin-dell.c | 5 +- plugins/udev/fu-rom.c | 4 +- src/fu-common-guid.c | 129 ++++++++++++++++++++++++++++++++++ src/fu-common-guid.h | 19 +++++ src/fu-device.c | 17 ++--- src/fu-engine.c | 7 +- src/fu-hwids.c | 10 +-- src/fu-quirks.c | 6 +- src/fu-self-test.c | 25 +++++++ src/meson.build | 10 +++ 10 files changed, 209 insertions(+), 23 deletions(-) create mode 100644 src/fu-common-guid.c create mode 100644 src/fu-common-guid.h diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 707aef12d..4c9364b3d 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -13,6 +13,7 @@ #include #include +#include "fu-common-guid.h" #include "fu-plugin-dell.h" #include "fu-plugin-vfuncs.h" #include "fu-device-metadata.h" @@ -597,11 +598,11 @@ fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error) } tpm_guid_raw = g_strdup_printf ("%04x-%s", system_id, tpm_mode); - tpm_guid = as_utils_guid_from_string (tpm_guid_raw); + tpm_guid = fu_common_guid_from_string (tpm_guid_raw); tpm_id = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid); tpm_guid_raw_alt = g_strdup_printf ("%04x-%s", system_id, tpm_mode_alt); - tpm_guid_alt = as_utils_guid_from_string (tpm_guid_raw_alt); + tpm_guid_alt = fu_common_guid_from_string (tpm_guid_raw_alt); tpm_id_alt = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid_alt); g_debug ("Creating primary TPM GUID %s and secondary TPM GUID %s", diff --git a/plugins/udev/fu-rom.c b/plugins/udev/fu-rom.c index 5f9917c45..0dc7c2dca 100644 --- a/plugins/udev/fu-rom.c +++ b/plugins/udev/fu-rom.c @@ -7,10 +7,10 @@ #include "config.h" #include -#include #include #include +#include "fu-common-guid.h" #include "fu-rom.h" static void fu_rom_finalize (GObject *object); @@ -689,7 +689,7 @@ fu_rom_load_data (FuRom *self, /* update guid */ id = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", self->vendor_id, self->device_id); - self->guid = as_utils_guid_from_string (id); + self->guid = fu_common_guid_from_string (id); g_debug ("using %s for %s", self->guid, id); /* not known */ diff --git a/src/fu-common-guid.c b/src/fu-common-guid.c new file mode 100644 index 000000000..fe9006604 --- /dev/null +++ b/src/fu-common-guid.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuCommon" + +#include + +#include +#include + +#include "fwupd-error.h" + +#include "fu-common-guid.h" + +/** + * fu_common_guid_from_data: + * @namespace_id: A namespace ID, e.g. "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + * @data: data to hash + * @data_len: length of @data + * @error: A #GError or %NULL + * + * Returns a GUID for some data. This uses a hash and so even small + * differences in the @data will produce radically different return values. + * + * The implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash. + * + * Returns: A new GUID, or %NULL if the namespace_id was invalid + * + * Since: 1.2.0 + **/ +gchar * +fu_common_guid_from_data (const gchar *namespace_id, + const guint8 *data, + gsize data_len, + GError **error) +{ + gchar guid_new[37]; /* 36 plus NUL */ + gsize digestlen = 20; + guint8 hash[20]; + gint rc; + uuid_t uu_namespace; + uuid_t uu_new; + g_autoptr(GChecksum) csum = NULL; + + g_return_val_if_fail (namespace_id != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data_len != 0, FALSE); + + /* convert the namespace to binary */ + rc = uuid_parse (namespace_id, uu_namespace); + if (rc != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "namespace '%s' is invalid", + namespace_id); + return FALSE; + } + + /* hash the namespace and then the string */ + csum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (csum, (guchar *) uu_namespace, 16); + g_checksum_update (csum, (guchar *) data, (gssize) data_len); + g_checksum_get_digest (csum, hash, &digestlen); + + /* copy most parts of the hash 1:1 */ + memcpy (uu_new, hash, 16); + + /* set specific bits according to Section 4.1.3 */ + uu_new[6] = (guint8) ((uu_new[6] & 0x0f) | (5 << 4)); + uu_new[8] = (guint8) ((uu_new[8] & 0x3f) | 0x80); + + /* return as a string */ + uuid_unparse (uu_new, guid_new); + return g_strdup (guid_new); +} + +/** + * fu_common_guid_is_valid: + * @guid: string to check + * + * Checks the source string is a valid string GUID descriptor. + * + * Returns: %TRUE if @guid was a valid GUID, %FALSE otherwise + * + * Since: 1.2.0 + **/ +gboolean +fu_common_guid_is_valid (const gchar *guid) +{ + gint rc; + uuid_t uu; + if (guid == NULL) + return FALSE; + rc = uuid_parse (guid, uu); + return rc == 0; +} + +/** + * fu_common_guid_from_string: + * @str: A source string to use as a key + * + * Returns a GUID for a given string. This uses a hash and so even small + * differences in the @str will produce radically different return values. + * + * The implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash with a DNS namespace. + * The same result can be obtained with this simple python program: + * + * #!/usr/bin/python + * import uuid + * print uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') + * + * Returns: A new GUID, or %NULL if the string was invalid + * + * Since: 1.2.0 + **/ +gchar * +fu_common_guid_from_string (const gchar *str) +{ + if (str == NULL) + return NULL; + return fu_common_guid_from_data ("6ba7b810-9dad-11d1-80b4-00c04fd430c8", + (const guint8 *) str, strlen (str), NULL); +} diff --git a/src/fu-common-guid.h b/src/fu-common-guid.h new file mode 100644 index 000000000..db6e50fa9 --- /dev/null +++ b/src/fu-common-guid.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_COMMON_GUID_H__ +#define __FU_COMMON_GUID_H__ + +#include + +gboolean fu_common_guid_is_valid (const gchar *guid); +gchar *fu_common_guid_from_string (const gchar *str); +gchar *fu_common_guid_from_data (const gchar *namespace_id, + const guint8 *data, + gsize data_len, + GError **error); + +#endif /* __FU_COMMON_GUID_H__ */ diff --git a/src/fu-device.c b/src/fu-device.c index bb427fba8..582736ab2 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -13,6 +13,7 @@ #include #include "fu-common.h" +#include "fu-common-guid.h" #include "fu-device-private.h" #include "fu-mutex.h" @@ -534,8 +535,8 @@ fu_device_add_parent_guid (FuDevice *self, const gchar *guid) g_return_if_fail (guid != NULL); /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); + if (!fu_common_guid_is_valid (guid)) { + g_autofree gchar *tmp = fu_common_guid_from_string (guid); if (fu_device_has_parent_guid (self, tmp)) return; g_debug ("using %s for %s", tmp, guid); @@ -769,7 +770,7 @@ fu_device_add_guid_safe (FuDevice *self, const gchar *guid) * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` * * Adds a GUID to the device. If the @guid argument is not a valid GUID then it - * is converted to a GUID using as_utils_guid_from_string(). + * is converted to a GUID using fu_common_guid_from_string(). * * Since: 0.7.2 **/ @@ -777,8 +778,8 @@ void fu_device_add_guid (FuDevice *self, const gchar *guid) { /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); + if (!fu_common_guid_is_valid (guid)) { + g_autofree gchar *tmp = fu_common_guid_from_string (guid); g_debug ("using %s for %s", tmp, guid); fu_device_add_guid_safe (self, tmp); return; @@ -794,7 +795,7 @@ fu_device_add_guid (FuDevice *self, const gchar *guid) * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` * * Adds a GUID to the device. If the @guid argument is not a valid GUID then it - * is converted to a GUID using as_utils_guid_from_string(). + * is converted to a GUID using fu_common_guid_from_string(). * * A counterpart GUID is typically the GUID of the same device in bootloader * or runtime mode, if they have a different device PCI or USB ID. Adding this @@ -806,8 +807,8 @@ void fu_device_add_counterpart_guid (FuDevice *self, const gchar *guid) { /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); + if (!fu_common_guid_is_valid (guid)) { + g_autofree gchar *tmp = fu_common_guid_from_string (guid); g_debug ("using %s for counterpart %s", tmp, guid); fwupd_device_add_guid (FWUPD_DEVICE (self), tmp); return; diff --git a/src/fu-engine.c b/src/fu-engine.c index 5c4126640..0d9b524e2 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -25,6 +25,7 @@ #include "fwupd-resources.h" #include "fu-common-cab.h" +#include "fu-common-guid.h" #include "fu-common.h" #include "fu-config.h" #include "fu-debug.h" @@ -824,7 +825,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, } /* another device */ - if (as_utils_guid_is_valid (as_require_get_value (req))) { + if (fu_common_guid_is_valid (as_require_get_value (req))) { const gchar *guid = as_require_get_value (req); const gchar *version; g_autoptr(FuDevice) device2 = NULL; @@ -996,9 +997,9 @@ fu_engine_vendor_fixup_provide_value (AsApp *app) g_autofree gchar *guid = NULL; if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) continue; - if (as_utils_guid_is_valid (value)) + if (fu_common_guid_is_valid (value)) continue; - guid = as_utils_guid_from_string (value); + guid = fu_common_guid_from_string (value); as_provide_set_value (prov, guid); } } diff --git a/src/fu-hwids.c b/src/fu-hwids.c index c436e2bdb..b72af2c5e 100644 --- a/src/fu-hwids.c +++ b/src/fu-hwids.c @@ -11,9 +11,9 @@ #include #include #include -#include #include "fu-common.h" +#include "fu-common-guid.h" #include "fu-hwids.h" #include "fwupd-error.h" @@ -97,10 +97,10 @@ fu_hwids_get_guid_for_str (const gchar *str, GError **error) data[i] = GUINT16_TO_LE(data[i]); /* convert to a GUID */ - return as_utils_guid_from_data (namespace_id, - (guint8*) data, - items_written * 2, - error); + return fu_common_guid_from_data (namespace_id, + (guint8*) data, + items_written * 2, + error); } /** diff --git a/src/fu-quirks.c b/src/fu-quirks.c index 2f6ead814..c41845d30 100644 --- a/src/fu-quirks.c +++ b/src/fu-quirks.c @@ -11,9 +11,9 @@ #include #include #include -#include #include "fu-common.h" +#include "fu-common-guid.h" #include "fu-mutex.h" #include "fu-quirks.h" @@ -97,9 +97,9 @@ fu_quirks_build_group_key (const gchar *group) for (guint i = 0; guid_prefixes[i] != NULL; i++) { if (g_str_has_prefix (group, guid_prefixes[i])) { gsize len = strlen (guid_prefixes[i]); - if (as_utils_guid_is_valid (group + len)) + if (fu_common_guid_is_valid (group + len)) return g_strdup (group + len); - return as_utils_guid_from_string (group + len); + return fu_common_guid_from_string (group + len); } } diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 4f359614e..b779f2350 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -16,6 +16,7 @@ #include #include "fu-common-cab.h" +#include "fu-common-guid.h" #include "fu-chunk.h" #include "fu-config.h" #include "fu-device-list.h" @@ -2838,6 +2839,29 @@ fu_common_strstrip_func (void) } } +static void +fu_common_guid_func (void) +{ + g_autofree gchar *guid1 = NULL; + g_autofree gchar *guid2 = NULL; + + /* invalid */ + g_assert (!fu_common_guid_is_valid (NULL)); + g_assert (!fu_common_guid_is_valid ("")); + g_assert (!fu_common_guid_is_valid ("1ff60ab2-3905-06a1-b476")); + g_assert (!fu_common_guid_is_valid ("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9b")); + g_assert (!fu_common_guid_is_valid (" 1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + + /* valid */ + g_assert (fu_common_guid_is_valid ("1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + + /* make valid */ + guid1 = fu_common_guid_from_string ("python.org"); + g_assert_cmpstr (guid1, ==, "886313e1-3b8a-5372-9b90-0c9aee199e5d"); + guid2 = fu_common_guid_from_string ("8086:0406"); + g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486"); +} + int main (int argc, char **argv) { @@ -2899,6 +2923,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func); g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{guid}", fu_common_guid_func); g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func); g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func); g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func); diff --git a/src/meson.build b/src/meson.build index 61a1db6c4..b5bedb0d4 100644 --- a/src/meson.build +++ b/src/meson.build @@ -26,6 +26,7 @@ libfwupdprivate = static_library( 'fwupdprivate', sources : [ 'fu-common.c', + 'fu-common-guid.c', 'fu-chunk.c', 'fu-device.c', 'fu-device-locker.c', @@ -53,6 +54,7 @@ libfwupdprivate = static_library( sqlite, libarchive, valgrind, + uuid, ], c_args : [ '-DFU_OFFLINE_DESTDIR=""', @@ -108,6 +110,7 @@ fwupdtool = executable( 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -145,6 +148,7 @@ fwupdtool = executable( sqlite, valgrind, libarchive, + uuid, ], link_with : [ fwupd, @@ -184,6 +188,7 @@ executable( 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -223,6 +228,7 @@ executable( sqlite, valgrind, libarchive, + uuid, ], link_with : fwupd, c_args : [ @@ -251,6 +257,7 @@ if get_option('tests') 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', 'fu-config.c', 'fu-engine.c', 'fu-keyring.c', @@ -289,6 +296,7 @@ if get_option('tests') sqlite, valgrind, libarchive, + uuid, ], link_with : [ fwupd, @@ -312,6 +320,8 @@ if get_option('introspection') 'fu-chunk.c', 'fu-chunk.h', 'fu-common.c', + 'fu-common-guid.c', + 'fu-common-guid.h', 'fu-common.h', 'fu-device.c', 'fu-device.h', From 05cbb7245c63a94b0289a6baec42896890da2640 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:20:39 +0100 Subject: [PATCH 004/254] Don't use AppStream-glib for version helpers Refactor the imported version format code now we now longer need to stick to the API mistakes of libappstream-glib. --- plugins/dell/fu-plugin-dell.c | 28 ++-- plugins/dfu/dfu-firmware.c | 7 +- plugins/dfu/dfu-tool.c | 5 +- plugins/dfu/fu-plugin-dfu.c | 2 - plugins/nvme/fu-nvme-device.c | 2 +- plugins/uefi/fu-plugin-uefi.c | 24 ++- src/fu-common-version.c | 307 ++++++++++++++++++++++++++++++++++ src/fu-common-version.h | 45 +++++ src/fu-engine.c | 8 +- src/fu-install-task.c | 5 +- src/fu-plugin.h | 2 + src/fu-self-test.c | 131 +++++++++++++++ src/fu-usb-device.c | 6 +- src/fu-util.c | 4 +- src/meson.build | 6 + 15 files changed, 533 insertions(+), 49 deletions(-) create mode 100644 src/fu-common-version.c create mode 100644 src/fu-common-version.h diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 4c9364b3d..b7bd83f57 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -232,7 +232,7 @@ fu_plugin_dell_inject_fake_data (FuPlugin *plugin, data->can_switch_modes = TRUE; } -static AsVersionParseFlag +static FuVersionFormat fu_plugin_dell_get_version_format (FuPlugin *plugin) { const gchar *content; @@ -241,17 +241,15 @@ fu_plugin_dell_get_version_format (FuPlugin *plugin) content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); if (content == NULL) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FU_VERSION_FORMAT_TRIPLET; /* any quirks match */ group = g_strdup_printf ("SmbiosManufacturer=%s", content); quirk = fu_plugin_lookup_quirk_by_id (plugin, group, FU_QUIRKS_UEFI_VERSION_FORMAT); - if (g_strcmp0 (quirk, "quad") == 0) - return AS_VERSION_PARSE_FLAG_NONE; - - /* fall back */ - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + if (quirk == NULL) + return FU_VERSION_FORMAT_TRIPLET; + return fu_common_version_format_from_string (quirk); } static gboolean @@ -319,7 +317,7 @@ fu_plugin_usb_device_added (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - AsVersionParseFlag parse_flags; + FuVersionFormat version_format; guint16 pid; guint16 vid; const gchar *query_str; @@ -372,7 +370,7 @@ fu_plugin_usb_device_added (FuPlugin *plugin, g_debug ("Dock cable type: %" G_GUINT32_FORMAT, dock_info->cable_type); g_debug ("Dock location: %d", dock_info->location); g_debug ("Dock component count: %d", dock_info->component_count); - parse_flags = fu_plugin_dell_get_version_format (plugin); + version_format = fu_plugin_dell_get_version_format (plugin); for (guint i = 0; i < dock_info->component_count; i++) { g_autofree gchar *fw_str = NULL; @@ -411,8 +409,8 @@ fu_plugin_usb_device_added (FuPlugin *plugin, continue; } - fw_str = as_utils_version_from_uint32 (dock_info->components[i].fw_version, - parse_flags); + fw_str = fu_common_version_from_uint32 (dock_info->components[i].fw_version, + version_format); if (!fu_plugin_dock_node (plugin, platform, buf.record->dock_info_header.dock_type, @@ -427,8 +425,8 @@ fu_plugin_usb_device_added (FuPlugin *plugin, /* if an old EC or invalid EC version found, create updatable parent */ if (old_ec) - flash_ver_str = as_utils_version_from_uint32 (dock_info->flash_pkg_version, - parse_flags); + flash_ver_str = fu_common_version_from_uint32 (dock_info->flash_pkg_version, + version_format); if (!fu_plugin_dock_node (plugin, platform, buf.record->dock_info_header.dock_type, @@ -607,8 +605,8 @@ fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error) g_debug ("Creating primary TPM GUID %s and secondary TPM GUID %s", tpm_guid_raw, tpm_guid_raw_alt); - version_str = as_utils_version_from_uint32 (out->fw_version, - AS_VERSION_PARSE_FLAG_NONE); + version_str = fu_common_version_from_uint32 (out->fw_version, + FU_VERSION_FORMAT_QUAD); /* make it clear that the TPM is a discrete device of the product */ if (!data->smi_obj->fake_smbios) { diff --git a/plugins/dfu/dfu-firmware.c b/plugins/dfu/dfu-firmware.c index 1b56afd42..1b8b5111c 100644 --- a/plugins/dfu/dfu-firmware.c +++ b/plugins/dfu/dfu-firmware.c @@ -21,7 +21,8 @@ #include #include -#include + +#include "fu-common-version.h" #include "dfu-common.h" #include "dfu-firmware.h" @@ -642,8 +643,8 @@ dfu_firmware_to_string (DfuFirmware *firmware) g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); - release_str = as_utils_version_from_uint16 (priv->release, - AS_VERSION_PARSE_FLAG_USE_BCD); + release_str = fu_common_version_from_uint16 (priv->release, + FU_VERSION_FORMAT_BCD); str = g_string_new (""); g_string_append_printf (str, "vid: 0x%04x\n", priv->vid); g_string_append_printf (str, "pid: 0x%04x\n", priv->pid); diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index 03672b632..e9c7e2dc0 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "dfu-cipher-xtea.h" #include "dfu-device-private.h" @@ -2036,8 +2035,8 @@ dfu_tool_list (DfuToolPrivate *priv, gchar **values, GError **error) dfu_device_set_usb_context (device, usb_context); if (!fu_device_probe (FU_DEVICE (device), NULL)) continue; - version = as_utils_version_from_uint16 (g_usb_device_get_release (usb_device), - AS_VERSION_PARSE_FLAG_USE_BCD); + version = fu_common_version_from_uint16 (g_usb_device_get_release (usb_device), + FU_VERSION_FORMAT_BCD); g_print ("%s %04x:%04x [v%s]:\n", /* TRANSLATORS: detected a DFU device */ _("Found"), diff --git a/plugins/dfu/fu-plugin-dfu.c b/plugins/dfu/fu-plugin-dfu.c index dca1cfc56..64af9951d 100644 --- a/plugins/dfu/fu-plugin-dfu.c +++ b/plugins/dfu/fu-plugin-dfu.c @@ -6,8 +6,6 @@ #include "config.h" -#include - #include "fu-plugin-vfuncs.h" #include "dfu-device.h" diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 060f7a423..2c9518385 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -203,7 +203,7 @@ fu_nvme_device_set_version (FuNvmeDevice *self, const gchar *version, GError **e version); return FALSE; } - version_new = as_utils_version_from_uint32 (tmp, AS_VERSION_PARSE_FLAG_NONE); + version_new = as_utils_version_from_uint32 (tmp, FU_VERSION_FORMAT_QUAD); fu_device_set_version (FU_DEVICE (self), version_new); return TRUE; } diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 44876910c..59de81ac5 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -412,7 +412,7 @@ fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) } } -static AsVersionParseFlag +static FuVersionFormat fu_plugin_uefi_get_version_format_for_type (FuPlugin *plugin, FuUefiDeviceKind device_kind) { const gchar *content; @@ -421,21 +421,19 @@ fu_plugin_uefi_get_version_format_for_type (FuPlugin *plugin, FuUefiDeviceKind d /* we have no information for devices */ if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FU_VERSION_FORMAT_TRIPLET; content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); if (content == NULL) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FU_VERSION_FORMAT_TRIPLET; /* any quirks match */ group = g_strdup_printf ("SmbiosManufacturer=%s", content); quirk = fu_plugin_lookup_quirk_by_id (plugin, group, FU_QUIRKS_UEFI_VERSION_FORMAT); - if (g_strcmp0 (quirk, "quad") == 0) - return AS_VERSION_PARSE_FLAG_NONE; - - /* fall back */ - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + if (quirk == NULL) + return FU_VERSION_FORMAT_TRIPLET; + return fu_common_version_format_from_string (quirk); } static const gchar * @@ -478,7 +476,7 @@ static gboolean fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **error) { FuUefiDeviceKind device_kind; - AsVersionParseFlag parse_flags; + FuVersionFormat version_format; guint32 version_raw; g_autofree gchar *name = NULL; g_autofree gchar *version_lowest = NULL; @@ -486,17 +484,17 @@ fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **er /* add details to the device */ device_kind = fu_uefi_device_get_kind (dev); - parse_flags = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind); + version_format = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind); version_raw = fu_uefi_device_get_version (dev); - version = as_utils_version_from_uint32 (version_raw, parse_flags); + version = fu_common_version_from_uint32 (version_raw, version_format); fu_device_set_version (dev, version); name = fu_plugin_uefi_get_name_for_type (plugin, fu_uefi_device_get_kind (dev)); if (name != NULL) fu_device_set_name (FU_DEVICE (dev), name); version_raw = fu_uefi_device_get_version_lowest (dev); if (version_raw != 0) { - version_lowest = as_utils_version_from_uint32 (version_raw, - parse_flags); + version_lowest = fu_common_version_from_uint32 (version_raw, + version_format); fu_device_set_version_lowest (FU_DEVICE (dev), version_lowest); } fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_INTERNAL); diff --git a/src/fu-common-version.c b/src/fu-common-version.c new file mode 100644 index 000000000..5088cfc31 --- /dev/null +++ b/src/fu-common-version.c @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuCommon" + +#include + +#include + +#include "fwupd-error.h" + +#include "fu-common-version.h" + +#define FU_COMMON_VERSION_DECODE_BCD(val) ((((val) >> 4) & 0x0f) * 10 + ((val) & 0x0f)) + +/** + * fu_common_version_format_from_string: + * @str: A string, e.g. `quad` + * + * Converts text to a display version type. + * + * Returns: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Since: 1.2.0 + **/ +FuVersionFormat +fu_common_version_format_from_string (const gchar *str) +{ + if (g_strcmp0 (str, "triplet") == 0) + return FU_VERSION_FORMAT_TRIPLET; + if (g_strcmp0 (str, "quad") == 0) + return FU_VERSION_FORMAT_QUAD; + if (g_strcmp0 (str, "bcd") == 0) + return FU_VERSION_FORMAT_BCD; + if (g_strcmp0 (str, "plain") == 0) + return FU_VERSION_FORMAT_PLAIN; + return FU_VERSION_FORMAT_QUAD; +} + +/** + * fu_common_version_format_to_string: + * @str: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Converts a display version type to text. + * + * Returns: A string, e.g. `quad`, or %NULL if not known + * + * Since: 1.2.0 + **/ +const gchar * +fu_common_version_format_to_string (FuVersionFormat kind) +{ + if (kind == FU_VERSION_FORMAT_TRIPLET) + return "triplet"; + if (kind == FU_VERSION_FORMAT_QUAD) + return "quad"; + if (kind == FU_VERSION_FORMAT_BCD) + return "bcd"; + if (kind == FU_VERSION_FORMAT_PLAIN) + return "plain"; + return NULL; +} + +/** + * fu_common_version_from_uint32: + * @val: A uint32le version number + * @kind: version kind used for formatting, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Returns a dotted decimal version string from a 32 bit number. + * + * Returns: A version number, e.g. "1.0.3", or %NULL if not supported + * + * Since: 1.2.0 + **/ +gchar * +fu_common_version_from_uint32 (guint32 val, FuVersionFormat kind) +{ + if (kind == FU_VERSION_FORMAT_QUAD) { + /* AA.BB.CC.DD */ + return g_strdup_printf ("%u.%u.%u.%u", + (val >> 24) & 0xff, + (val >> 16) & 0xff, + (val >> 8) & 0xff, + val & 0xff); + } + if (kind == FU_VERSION_FORMAT_TRIPLET) { + /* AA.BB.CCDD */ + return g_strdup_printf ("%u.%u.%u", + (val >> 24) & 0xff, + (val >> 16) & 0xff, + val & 0xffff); + } + if (kind == FU_VERSION_FORMAT_PAIR) { + /* AABB.CCDD */ + return g_strdup_printf ("%u.%u", + (val >> 16) & 0xffff, + val & 0xffff); + } + if (kind == FU_VERSION_FORMAT_PLAIN) { + /* AABBCCDD */ + return g_strdup_printf ("%" G_GUINT32_FORMAT, val); + } + if (kind == FU_VERSION_FORMAT_BCD) { + /* AA.BB.CC.DD, but BCD */ + return g_strdup_printf ("%u.%u.%u.%u", + FU_COMMON_VERSION_DECODE_BCD(val >> 24), + FU_COMMON_VERSION_DECODE_BCD(val >> 16), + FU_COMMON_VERSION_DECODE_BCD(val >> 8), + FU_COMMON_VERSION_DECODE_BCD(val)); + } + return NULL; +} + +/** + * fu_common_version_from_uint16: + * @val: A uint16le version number + * @kind: version kind used for formatting, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Returns a dotted decimal version string from a 16 bit number. + * + * Returns: A version number, e.g. "1.3", or %NULL if not supported + * + * Since: 1.2.0 + **/ +gchar * +fu_common_version_from_uint16 (guint16 val, FuVersionFormat kind) +{ + if (kind == FU_VERSION_FORMAT_BCD) { + return g_strdup_printf ("%i.%i", + FU_COMMON_VERSION_DECODE_BCD(val >> 8), + FU_COMMON_VERSION_DECODE_BCD(val)); + } + if (kind == FU_VERSION_FORMAT_PAIR) { + return g_strdup_printf ("%u.%u", + (guint) (val >> 8) & 0xff, + (guint) val & 0xff); + } + if (kind == FU_VERSION_FORMAT_PLAIN) { + return g_strdup_printf ("%" G_GUINT16_FORMAT, val); + } + return NULL; +} + +static gint +fu_common_vercmp_char (gchar chr1, gchar chr2) +{ + if (chr1 == chr2) + return 0; + if (chr1 == '~') + return -1; + if (chr2 == '~') + return 1; + return chr1 < chr2 ? -1 : 1; +} + +static gint +fu_common_vercmp_chunk (const gchar *str1, const gchar *str2) +{ + guint i; + + /* trivial */ + if (g_strcmp0 (str1, str2) == 0) + return 0; + if (str1 == NULL) + return 1; + if (str2 == NULL) + return -1; + + /* check each char of the chunk */ + for (i = 0; str1[i] != '\0' && str2[i] != '\0'; i++) { + gint rc = fu_common_vercmp_char (str1[i], str2[i]); + if (rc != 0) + return rc; + } + return fu_common_vercmp_char (str1[i], str2[i]); +} + +/** + * fu_common_version_parse: + * @version: A version number + * + * Returns a dotted decimal version string from a version string. The supported + * formats are: + * + * - Dotted decimal, e.g. "1.2.3" + * - Base 16, a hex number *with* a 0x prefix, e.g. "0x10203" + * - Base 10, a string containing just [0-9], e.g. "66051" + * - Date in YYYYMMDD format, e.g. 20150915 + * + * Anything with a '.' or that doesn't match [0-9] or 0x[a-f,0-9] is considered + * a string and returned without modification. + * + * Returns: A version number, e.g. "1.0.3" + * + * Since: 1.2.0 + */ +gchar * +fu_common_version_parse (const gchar *version) +{ + const gchar *version_noprefix = version; + gchar *endptr = NULL; + guint64 tmp; + guint base; + guint i; + + /* already dotted decimal */ + if (g_strstr_len (version, -1, ".") != NULL) + return g_strdup (version); + + /* is a date */ + if (g_str_has_prefix (version, "20") && + strlen (version) == 8) + return g_strdup (version); + + /* convert 0x prefixed strings to dotted decimal */ + if (g_str_has_prefix (version, "0x")) { + version_noprefix += 2; + base = 16; + } else { + /* for non-numeric content, just return the string */ + for (i = 0; version[i] != '\0'; i++) { + if (!g_ascii_isdigit (version[i])) + return g_strdup (version); + } + base = 10; + } + + /* convert */ + tmp = g_ascii_strtoull (version_noprefix, &endptr, base); + if (endptr != NULL && endptr[0] != '\0') + return g_strdup (version); + if (tmp == 0) + return g_strdup (version); + return fu_common_version_from_uint32 ((guint32) tmp, FU_VERSION_FORMAT_TRIPLET); +} + +/** + * fu_common_vercmp: + * @version_a: the release version, e.g. 1.2.3 + * @version_b: the release version, e.g. 1.2.3.1 + * + * Compares version numbers for sorting. + * + * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error + * + * Since: 0.3.5 + */ +gint +fu_common_vercmp (const gchar *version_a, const gchar *version_b) +{ + guint longest_split; + g_autofree gchar *str_a = NULL; + g_autofree gchar *str_b = NULL; + g_auto(GStrv) split_a = NULL; + g_auto(GStrv) split_b = NULL; + + /* sanity check */ + if (version_a == NULL || version_b == NULL) + return G_MAXINT; + + /* optimisation */ + if (g_strcmp0 (version_a, version_b) == 0) + return 0; + + /* split into sections, and try to parse */ + str_a = fu_common_version_parse (version_a); + str_b = fu_common_version_parse (version_b); + split_a = g_strsplit (str_a, ".", -1); + split_b = g_strsplit (str_b, ".", -1); + longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b)); + for (guint i = 0; i < longest_split; i++) { + gchar *endptr_a = NULL; + gchar *endptr_b = NULL; + gint64 ver_a; + gint64 ver_b; + + /* we lost or gained a dot */ + if (split_a[i] == NULL) + return -1; + if (split_b[i] == NULL) + return 1; + + /* compare integers */ + ver_a = g_ascii_strtoll (split_a[i], &endptr_a, 10); + ver_b = g_ascii_strtoll (split_b[i], &endptr_b, 10); + if (ver_a < ver_b) + return -1; + if (ver_a > ver_b) + return 1; + + /* compare strings */ + if ((endptr_a != NULL && endptr_a[0] != '\0') || + (endptr_b != NULL && endptr_b[0] != '\0')) { + gint rc = fu_common_vercmp_chunk (endptr_a, endptr_b); + if (rc < 0) + return -1; + if (rc > 0) + return 1; + } + } + + /* we really shouldn't get here */ + return 0; +} diff --git a/src/fu-common-version.h b/src/fu-common-version.h new file mode 100644 index 000000000..059fc4d83 --- /dev/null +++ b/src/fu-common-version.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_COMMON_VERSION_H__ +#define __FU_COMMON_VERSION_H__ + +#include + +/** + * FuVersionFormat: + * @FU_VERSION_FORMAT_UNKNOWN: Unknown version format + * @FU_VERSION_FORMAT_PLAIN: Use plain integer version numbers + * @FU_VERSION_FORMAT_QUAD: Use Dell-style AA.BB.CC.DD version numbers + * @FU_VERSION_FORMAT_TRIPLET: Use Microsoft-style AA.BB.CCDD version numbers + * @FU_VERSION_FORMAT_PAIR: Use two AABB.CCDD version numbers + * @FU_VERSION_FORMAT_BCD: Use binary coded decimal notation + * + * The flags used when parsing version numbers. + **/ +typedef enum { + FU_VERSION_FORMAT_UNKNOWN, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_PLAIN, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_QUAD, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_TRIPLET, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_PAIR, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_BCD, /* Since: 1.2.0 */ + /*< private >*/ + FU_VERSION_FORMAT_LAST +} FuVersionFormat; + +FuVersionFormat fu_common_version_format_from_string (const gchar *str); +const gchar *fu_common_version_format_to_string (FuVersionFormat kind); + +gint fu_common_vercmp (const gchar *version_a, + const gchar *version_b); +gchar *fu_common_version_from_uint32 (guint32 val, + FuVersionFormat flags); +gchar *fu_common_version_from_uint16 (guint16 val, + FuVersionFormat flags); +gchar *fu_common_version_parse (const gchar *version); + +#endif /* __FU_COMMON_VERSION_H__ */ diff --git a/src/fu-engine.c b/src/fu-engine.c index 0d9b524e2..e93e2faee 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1007,7 +1007,7 @@ fu_engine_vendor_fixup_provide_value (AsApp *app) static void fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app) { - AsVersionParseFlag flags = AS_VERSION_PARSE_FLAG_USE_TRIPLET; + FuVersionFormat flags = FU_VERSION_FORMAT_TRIPLET; GPtrArray *releases; const gchar *quirk; const gchar *version_format; @@ -1024,7 +1024,7 @@ fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app) g_auto(GStrv) globs = g_strsplit (quirk, ",", -1); for (guint i = 0; globs[i] != NULL; i++) { if (fnmatch (globs[i], as_app_get_id (app), 0) == 0) { - flags = AS_VERSION_PARSE_FLAG_NONE; + flags = FU_VERSION_FORMAT_QUAD; break; } } @@ -1033,7 +1033,7 @@ fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app) /* specified in metadata */ version_format = as_app_get_metadata_item (app, "LVFS::VersionFormat"); if (g_strcmp0 (version_format, "quad") == 0) - flags = AS_VERSION_PARSE_FLAG_NONE; + flags = FU_VERSION_FORMAT_QUAD; /* fix each release */ releases = as_app_get_releases (app); @@ -1056,7 +1056,7 @@ fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app) continue; /* convert to dotted decimal */ - version_new = as_utils_version_from_uint32 ((guint32) ver_uint32, flags); + version_new = fu_common_version_from_uint32 ((guint32) ver_uint32, flags); as_release_set_version (rel, version_new); } } diff --git a/src/fu-install-task.c b/src/fu-install-task.c index 4145eddbe..851abe0bb 100644 --- a/src/fu-install-task.c +++ b/src/fu-install-task.c @@ -10,6 +10,7 @@ #include +#include "fu-common-version.h" #include "fu-device-private.h" #include "fu-install-task.h" #include "fu-keyring-utils.h" @@ -210,7 +211,7 @@ fu_install_task_check_requirements (FuInstallTask *self, /* compare to the lowest supported version, if it exists */ version_lowest = fu_device_get_version_lowest (self->device); if (version_lowest != NULL && - as_utils_vercmp (version_lowest, version) > 0 && + fu_common_vercmp (version_lowest, version) > 0 && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { g_set_error (error, FWUPD_ERROR, @@ -221,7 +222,7 @@ fu_install_task_check_requirements (FuInstallTask *self, } /* check semver */ - vercmp = as_utils_vercmp (version, version_release); + vercmp = fu_common_vercmp (version, version_release); if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { g_set_error (error, FWUPD_ERROR, diff --git a/src/fu-plugin.h b/src/fu-plugin.h index 4177f8197..1375d9f9c 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -13,6 +13,8 @@ #include #include "fu-common.h" +#include "fu-common-guid.h" +#include "fu-common-version.h" #include "fu-device.h" #include "fu-device-locker.h" #include "fu-quirks.h" diff --git a/src/fu-self-test.c b/src/fu-self-test.c index b779f2350..be8c2c4f9 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -17,6 +17,7 @@ #include "fu-common-cab.h" #include "fu-common-guid.h" +#include "fu-common-version.h" #include "fu-chunk.h" #include "fu-config.h" #include "fu-device-list.h" @@ -2862,6 +2863,134 @@ fu_common_guid_func (void) g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486"); } +static void +fu_common_version_func (void) +{ + guint i; + struct { + guint32 val; + const gchar *ver; + FuVersionFormat flags; + } version_from_uint32[] = { + { 0x0, "0.0.0.0", FU_VERSION_FORMAT_QUAD }, + { 0xff, "0.0.0.255", FU_VERSION_FORMAT_QUAD }, + { 0xff01, "0.0.255.1", FU_VERSION_FORMAT_QUAD }, + { 0xff0001, "0.255.0.1", FU_VERSION_FORMAT_QUAD }, + { 0xff000100, "255.0.1.0", FU_VERSION_FORMAT_QUAD }, + { 0x0, "0.0.0", FU_VERSION_FORMAT_TRIPLET }, + { 0xff, "0.0.255", FU_VERSION_FORMAT_TRIPLET }, + { 0xff01, "0.0.65281", FU_VERSION_FORMAT_TRIPLET }, + { 0xff0001, "0.255.1", FU_VERSION_FORMAT_TRIPLET }, + { 0xff000100, "255.0.256", FU_VERSION_FORMAT_TRIPLET }, + { 0x0, "0", FU_VERSION_FORMAT_PLAIN }, + { 0xff000100, "4278190336", FU_VERSION_FORMAT_PLAIN }, + { 0, NULL } + }; + struct { + guint16 val; + const gchar *ver; + FuVersionFormat flags; + } version_from_uint16[] = { + { 0x0, "0.0", FU_VERSION_FORMAT_PAIR }, + { 0xff, "0.255", FU_VERSION_FORMAT_PAIR }, + { 0xff01, "255.1", FU_VERSION_FORMAT_PAIR }, + { 0x0, "0.0", FU_VERSION_FORMAT_BCD }, + { 0x0110, "1.10", FU_VERSION_FORMAT_BCD }, + { 0x9999, "99.99", FU_VERSION_FORMAT_BCD }, + { 0x0, "0", FU_VERSION_FORMAT_PLAIN }, + { 0x1234, "4660", FU_VERSION_FORMAT_PLAIN }, + { 0, NULL } + }; + struct { + const gchar *old; + const gchar *new; + } version_parse[] = { + { "0", "0" }, + { "0x1a", "0.0.26" }, + { "257", "0.0.257" }, + { "1.2.3", "1.2.3" }, + { "0xff0001", "0.255.1" }, + { "16711681", "0.255.1" }, + { "20150915", "20150915" }, + { "dave", "dave" }, + { "0x1x", "0x1x" }, + { NULL, NULL } + }; + + /* check version conversion */ + for (i = 0; version_from_uint32[i].ver != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_from_uint32 (version_from_uint32[i].val, + version_from_uint32[i].flags); + g_assert_cmpstr (ver, ==, version_from_uint32[i].ver); + } + for (i = 0; version_from_uint16[i].ver != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_from_uint16 (version_from_uint16[i].val, + version_from_uint16[i].flags); + g_assert_cmpstr (ver, ==, version_from_uint16[i].ver); + } + + /* check version parsing */ + for (i = 0; version_parse[i].old != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_parse (version_parse[i].old); + g_assert_cmpstr (ver, ==, version_parse[i].new); + } +} + +static void +fu_common_vercmp_func (void) +{ + /* same */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0); + + /* same, not dotted decimal */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "0x1020003"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("0x10203", "0x10203"), ==, 0); + + /* upgrade and downgrade */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.000", "001.002.009"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.2"), >, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.009", "001.002.000"), >, 0); + + /* unequal depth */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3.1"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3.1", "1.2.4"), <, 0); + + /* mixed-alpha-numeric */ + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3a"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3b"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3b", "1.2.3a"), >, 0); + + /* alpha version append */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3a"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3"), >, 0); + + /* alpha only */ + g_assert_cmpint (fu_common_vercmp ("alpha", "alpha"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("alpha", "beta"), <, 0); + g_assert_cmpint (fu_common_vercmp ("beta", "alpha"), >, 0); + + /* alpha-compare */ + g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2a.3"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2b.3"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2b.3", "1.2a.3"), >, 0); + + /* tilde is all-powerful */ + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3~rc1"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3~rc1"), >, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc2", "1.2.3~rc1"), >, 0); + + /* invalid */ + g_assert_cmpint (fu_common_vercmp ("1", NULL), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp (NULL, "1"), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT); +} + int main (int argc, char **argv) { @@ -2924,6 +3053,8 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); g_test_add_func ("/fwupd/common{guid}", fu_common_guid_func); + g_test_add_func ("/fwupd/common{version}", fu_common_version_func); + g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func); g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func); g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func); g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func); diff --git a/src/fu-usb-device.c b/src/fu-usb-device.c index bd455c6df..127d49429 100644 --- a/src/fu-usb-device.c +++ b/src/fu-usb-device.c @@ -8,8 +8,6 @@ #include "config.h" -#include - #include "fu-usb-device-private.h" /** @@ -238,8 +236,8 @@ fu_usb_device_probe (FuDevice *device, GError **error) /* set the version if the release has been set */ release = g_usb_device_get_release (priv->usb_device); if (release != 0x0) { - g_autofree gchar *version = as_utils_version_from_uint16 (release, - AS_VERSION_PARSE_FLAG_USE_BCD); + g_autofree gchar *version = NULL; + version = fu_common_version_from_uint16 (release, FU_VERSION_FORMAT_BCD); fu_device_set_version (device, version); } diff --git a/src/fu-util.c b/src/fu-util.c index 5c2d35b68..3ffa68b13 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -742,8 +742,8 @@ fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) continue; /* tell the user what's going to happen */ - vercmp = as_utils_vercmp (fwupd_device_get_version (dev), - fwupd_release_get_version (rel)); + vercmp = fu_common_vercmp (fwupd_device_get_version (dev), + fwupd_release_get_version (rel)); if (vercmp == 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second is a version number diff --git a/src/meson.build b/src/meson.build index b5bedb0d4..b4b816444 100644 --- a/src/meson.build +++ b/src/meson.build @@ -27,6 +27,7 @@ libfwupdprivate = static_library( sources : [ 'fu-common.c', 'fu-common-guid.c', + 'fu-common-version.c', 'fu-chunk.c', 'fu-device.c', 'fu-device-locker.c', @@ -111,6 +112,7 @@ fwupdtool = executable( 'fu-common.c', 'fu-common-cab.c', 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -189,6 +191,7 @@ executable( 'fu-common.c', 'fu-common-cab.c', 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -258,6 +261,7 @@ if get_option('tests') 'fu-common.c', 'fu-common-cab.c', 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-engine.c', 'fu-keyring.c', @@ -322,6 +326,8 @@ if get_option('introspection') 'fu-common.c', 'fu-common-guid.c', 'fu-common-guid.h', + 'fu-common-version.c', + 'fu-common-version.h', 'fu-common.h', 'fu-device.c', 'fu-device.h', From 83e56c1a6c760c93dd6451af2d901d186017ae61 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:24:41 +0100 Subject: [PATCH 005/254] Don't use AppStream-glib for string helpers --- src/fu-common.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ src/fu-common.h | 4 +++ src/fu-config.c | 4 +-- src/fu-device.c | 2 +- 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/fu-common.c b/src/fu-common.c index 51360d3d2..37d74953f 100644 --- a/src/fu-common.c +++ b/src/fu-common.c @@ -993,3 +993,68 @@ fu_common_get_path (FuPathKind path_kind) return NULL; } + +/** + * fu_common_string_replace: + * @string: The #GString to operate on + * @search: The text to search for + * @replace: The text to use for substitutions + * + * Performs multiple search and replace operations on the given string. + * + * Returns: the number of replacements done, or 0 if @search is not found. + * + * Since: 1.2.0 + **/ +guint +fu_common_string_replace (GString *string, const gchar *search, const gchar *replace) +{ + gchar *tmp; + guint count = 0; + gsize search_idx = 0; + gsize replace_len; + gsize search_len; + + g_return_val_if_fail (string != NULL, 0); + g_return_val_if_fail (search != NULL, 0); + g_return_val_if_fail (replace != NULL, 0); + + /* nothing to do */ + if (string->len == 0) + return 0; + + search_len = strlen (search); + replace_len = strlen (replace); + + do { + tmp = g_strstr_len (string->str + search_idx, -1, search); + if (tmp == NULL) + break; + + /* advance the counter in case @replace contains @search */ + search_idx = (gsize) (tmp - string->str); + + /* reallocate the string if required */ + if (search_len > replace_len) { + g_string_erase (string, + (gssize) search_idx, + (gssize) (search_len - replace_len)); + memcpy (tmp, replace, replace_len); + } else if (search_len < replace_len) { + g_string_insert_len (string, + (gssize) search_idx, + replace, + (gssize) (replace_len - search_len)); + /* we have to treat this specially as it could have + * been reallocated when the insertion happened */ + memcpy (string->str + search_idx, replace, replace_len); + } else { + /* just memcmp in the new string */ + memcpy (tmp, replace, replace_len); + } + search_idx += replace_len; + count++; + } while (TRUE); + + return count; +} diff --git a/src/fu-common.h b/src/fu-common.h index f605cc649..a14802a10 100644 --- a/src/fu-common.h +++ b/src/fu-common.h @@ -79,4 +79,8 @@ guint16 fu_common_read_uint16 (const guint8 *buf, guint32 fu_common_read_uint32 (const guint8 *buf, FuEndianType endian); +guint fu_common_string_replace (GString *string, + const gchar *search, + const gchar *replace); + #endif /* __FU_COMMON_H__ */ diff --git a/src/fu-config.c b/src/fu-config.c index c7aeba5b0..2d22a56a6 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -261,11 +261,11 @@ fu_config_add_remotes_for_path (FuConfig *self, const gchar *path, GError **erro tmp = g_hash_table_lookup (self->os_release, "NAME"); if (tmp == NULL) tmp = "this distribution"; - as_utils_string_replace (agreement_markup, "$OS_RELEASE:NAME$", tmp); + fu_common_string_replace (agreement_markup, "$OS_RELEASE:NAME$", tmp); tmp = g_hash_table_lookup (self->os_release, "BUG_REPORT_URL"); if (tmp == NULL) tmp = "https://github.com/hughsie/fwupd/issues"; - as_utils_string_replace (agreement_markup, "$OS_RELEASE:BUG_REPORT_URL$", tmp); + fu_common_string_replace (agreement_markup, "$OS_RELEASE:BUG_REPORT_URL$", tmp); fwupd_remote_set_agreement (remote, agreement_markup->str); } diff --git a/src/fu-device.c b/src/fu-device.c index 582736ab2..7e7bde909 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -1011,7 +1011,7 @@ fu_device_set_name (FuDevice *self, const gchar *value) } g_strdelimit (new->str, "_", ' '); - as_utils_string_replace (new, "(TM)", "™"); + fu_common_string_replace (new, "(TM)", "™"); fwupd_device_set_name (FWUPD_DEVICE (self), new->str); } From a3d5712b9fdac545494bb5e19ffffed58a63fcea Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:30:15 +0100 Subject: [PATCH 006/254] Allow setting the version format from a quirk entry --- plugins/nvme/fu-nvme-device.c | 22 ++++++------------ src/fu-device.c | 42 +++++++++++++++++++++++++++++++++++ src/fu-device.h | 4 ++++ src/fu-quirks.h | 11 +++++++++ 4 files changed, 64 insertions(+), 15 deletions(-) diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 2c9518385..234f5e01f 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -25,7 +25,6 @@ struct _FuNvmeDevice { FuUdevDevice parent_instance; - gchar *version_format; guint pci_depth; gint fd; guint64 write_block_size; @@ -186,13 +185,13 @@ static gboolean fu_nvme_device_set_version (FuNvmeDevice *self, const gchar *version, GError **error) { /* unset */ - if (self->version_format == NULL) { + if (fu_device_get_version_format (FU_DEVICE (self)) == FU_VERSION_FORMAT_UNKNOWN) { fu_device_set_version (FU_DEVICE (self), version); return TRUE; } /* AA.BB.CC.DD */ - if (g_strcmp0 (self->version_format, "quad") == 0) { + if (fu_device_get_version_format (FU_DEVICE (self)) == FU_VERSION_FORMAT_QUAD) { guint64 tmp = g_ascii_strtoull (version, NULL, 16); g_autofree gchar *version_new = NULL; if (tmp == 0 || tmp > G_MAXUINT32) { @@ -203,17 +202,16 @@ fu_nvme_device_set_version (FuNvmeDevice *self, const gchar *version, GError **e version); return FALSE; } - version_new = as_utils_version_from_uint32 (tmp, FU_VERSION_FORMAT_QUAD); + version_new = fu_common_version_from_uint32 (tmp, FU_VERSION_FORMAT_QUAD); fu_device_set_version (FU_DEVICE (self), version_new); return TRUE; } /* invalid, or not supported */ - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "version format %s not recognised", - self->version_format); + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "version format not recognised"); return FALSE; } @@ -422,10 +420,6 @@ fu_nvme_device_set_quirk_kv (FuDevice *device, GError **error) { FuNvmeDevice *self = FU_NVME_DEVICE (device); - if (g_strcmp0 (key, "NvmeVersionFormat") == 0) { - self->version_format = g_strdup (value); - return TRUE; - } if (g_strcmp0 (key, "NvmeBlockSize") == 0) { self->write_block_size = fu_common_strtoull (value); return TRUE; @@ -451,8 +445,6 @@ fu_nvme_device_init (FuNvmeDevice *self) static void fu_nvme_device_finalize (GObject *object) { - FuNvmeDevice *self = FU_NVME_DEVICE (object); - g_free (self->version_format); G_OBJECT_CLASS (fu_nvme_device_parent_class)->finalize (object); } diff --git a/src/fu-device.c b/src/fu-device.c index 7e7bde909..b03dbfb9a 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -43,6 +43,7 @@ typedef struct { GPtrArray *children; guint remove_delay; /* ms */ FwupdStatus status; + FuVersionFormat version_format; guint progress; guint order; guint priority; @@ -676,6 +677,10 @@ fu_device_set_quirk_kv (FuDevice *self, fu_device_set_install_duration (self, fu_common_strtoull (value)); return TRUE; } + if (g_strcmp0 (key, FU_QUIRKS_VERSION_FORMAT) == 0) { + fu_device_set_version_format (self, fu_common_version_format_from_string (value)); + return TRUE; + } if (g_strcmp0 (key, FU_QUIRKS_CHILDREN) == 0) { g_auto(GStrv) sections = g_strsplit (value, ",", -1); for (guint i = 0; sections[i] != NULL; i++) { @@ -1351,6 +1356,43 @@ fu_device_set_status (FuDevice *self, FwupdStatus status) g_object_notify (G_OBJECT (self), "status"); } +/** + * fu_device_get_version_format: + * @self: A #FuDevice + * + * Returns how the device version should be formatted. + * + * Returns: the version format, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Since: 1.2.0 + **/ +FuVersionFormat +fu_device_get_version_format (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); + return priv->version_format; +} + +/** + * fu_device_set_version_format: + * @self: A #FuDevice + * @version_format: the version_format value, e.g. %FU_VERSION_FORMAT_TRIPLET + * + * Sets how the version should be formatted. + * + * Since: 1.2.0 + **/ +void +fu_device_set_version_format (FuDevice *self, FuVersionFormat version_format) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + if (priv->version_format == version_format) + return; + priv->version_format = version_format; +} + /** * fu_device_get_progress: * @self: A #FuDevice diff --git a/src/fu-device.h b/src/fu-device.h index 3f421d41a..1b80db894 100644 --- a/src/fu-device.h +++ b/src/fu-device.h @@ -11,6 +11,7 @@ #include #include "fu-quirks.h" +#include "fu-common-version.h" G_BEGIN_DECLS @@ -176,6 +177,9 @@ void fu_device_set_remove_delay (FuDevice *self, FwupdStatus fu_device_get_status (FuDevice *self); void fu_device_set_status (FuDevice *self, FwupdStatus status); +FuVersionFormat fu_device_get_version_format (FuDevice *self); +void fu_device_set_version_format (FuDevice *self, + FuVersionFormat version_format); void fu_device_set_firmware_size_min (FuDevice *self, guint64 size_min); void fu_device_set_firmware_size_max (FuDevice *self, diff --git a/src/fu-quirks.h b/src/fu-quirks.h index c677de157..02d4947fd 100644 --- a/src/fu-quirks.h +++ b/src/fu-quirks.h @@ -242,6 +242,17 @@ gboolean fu_quirks_get_kvs_for_guid (FuQuirks *self, */ #define FU_QUIRKS_INSTALL_DURATION "InstallDuration" +/** + * FU_QUIRKS_VERSION_FORMAT: + * @key: the device ID, e.g. `HwId=USB\VID_0763&PID_2806` + * @value: the quirk format, e.g. `quad` + * + * Sets the version format the device should use for conversion. + * + * Since: 1.2.0 + */ +#define FU_QUIRKS_VERSION_FORMAT "VersionFormat" + G_END_DECLS #endif /* __FU_QUIRKS_H */ From 2b9ba9f756f37acbdf81bebc6d69e82e0d98c54c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:32:07 +0100 Subject: [PATCH 007/254] trivial: Don't care so much about the AppStream-glib version --- src/fu-util-common.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/fu-util-common.c b/src/fu-util-common.c index 249088e13..af952e81a 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -6,7 +6,6 @@ #include -#include #include #include #include @@ -162,11 +161,6 @@ fu_util_get_versions (void) #endif g_string_append_printf (string, "compile-time dependency versions\n"); - g_string_append_printf (string, - "\tappstream-glib:\t%d.%d.%d\n", - AS_MAJOR_VERSION, - AS_MINOR_VERSION, - AS_MICRO_VERSION); g_string_append_printf (string, "\tgusb:\t%d.%d.%d\n", G_USB_MAJOR_VERSION, From 416ade7f3028e5fcce2fe57ad8defc8a49199ab9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:36:53 +0100 Subject: [PATCH 008/254] trivial: Hardcode the AppStream-glib version This is the version we've imported from, which allows cabinet files requiring a specific version of this library to continue working. --- src/fu-engine.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index e93e2faee..7bfa668ed 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -8,7 +8,6 @@ #include "config.h" -#include #include #include #include @@ -3786,9 +3785,7 @@ fu_engine_init (FuEngine *self) /* add some runtime versions of things the daemon depends on */ fu_engine_add_runtime_version (self, "org.freedesktop.fwupd", VERSION); fu_engine_add_runtime_version (self, "com.redhat.fwupdate", "12"); -#if AS_CHECK_VERSION(0,7,8) - fu_engine_add_runtime_version (self, "org.freedesktop.appstream-glib", as_version_string ()); -#endif + fu_engine_add_runtime_version (self, "org.freedesktop.appstream-glib", "0.7.14"); #if G_USB_CHECK_VERSION(0,3,1) fu_engine_add_runtime_version (self, "org.freedesktop.gusb", g_usb_version_string ()); #endif From 2ea87013cd675d9ea5a65547b36a31731831ce6e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 10 Oct 2018 22:29:16 -0500 Subject: [PATCH 009/254] contrib: Add information on how to use debugging scripts At least for me it was a challenge to get the debugger properly configured to allow debugging fwupd when built in tree. This should allow very simple debugging. --- contrib/vscode/README.md | 39 ++++++++++++++++++++++ contrib/vscode/build.sh | 32 ++++++++++++++++++ contrib/vscode/launch.json | 68 ++++++++++++++++++++++++++++++++++++++ contrib/vscode/launcher.sh | 8 +++++ 4 files changed, 147 insertions(+) create mode 100644 contrib/vscode/README.md create mode 100755 contrib/vscode/build.sh create mode 100644 contrib/vscode/launch.json create mode 100755 contrib/vscode/launcher.sh diff --git a/contrib/vscode/README.md b/contrib/vscode/README.md new file mode 100644 index 000000000..7d9f35f72 --- /dev/null +++ b/contrib/vscode/README.md @@ -0,0 +1,39 @@ +# Using Visual Studio Code to debug + +This directory contains a collection of scripts and assets to make debugging using Visual Studio Code easier. + +## Preparing +First install the following applications locally: +* GDB Server +* GDB +* Visual Studio Code + +In Visual Studio code, visit the extension store and install *C/C++* which is an extension provided by Microsoft. +Configure Visual Studio code to open the folder representing the root of the fwupd checkout. + +## Building +Run `./contrib/debugging/build.sh` to build fwupd with all default options and create helper scripts pre-configured for debugger use. +The application will be placed into `./dist` and helper scripts will be created for `fwupdtool`, `fwupdmgr`, and `fwupd`. + +## Running +To run any of the applications, execute the appropriate helper script in `./dist`. + +## Debugging +To debug any of the applications, launch the helper script with the environment variable `DEBUG` set. +For example to debug `fwupdtool get-devices` the command to launch would be: + +``` +sudo DEBUG=1 ./dist/fwupdtool.sh get-devices +``` + +This will configure `gdbserver` to listen on a local port waiting for a debugger to connect. + +## Using Visual Studio code +During build time a set of launch targets will have been created for use with Visual Studio Code. + +Press the debugging button on the left and 3 targets will be listed at the top. +* gdbserver (fwupdtool) +* gdbserver (fwupd) +* gdbserver (fwupdmgr) + +Select the appropriate target and press the green arrow to connect to `gdbserver` and start debugging. diff --git a/contrib/vscode/build.sh b/contrib/vscode/build.sh new file mode 100755 index 000000000..3420ba56c --- /dev/null +++ b/contrib/vscode/build.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# Copyright (C) 2018 Dell, Inc. + +SOURCE=$(dirname $0) +ROOT=$1 +if [ -z "$ROOT" ]; then + ROOT=`pwd` +fi + +# build in tree +rm -rf build ${ROOT}/dist +meson build --prefix=${ROOT}/dist -Dsystemd=false -Dudevdir=${ROOT}/dist +ninja -C build install + +#create helper scripts +TEMPLATE=${SOURCE}/launcher.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,libexec/fwupd/fwupd," \ + ${TEMPLATE} > ${ROOT}/dist/fwupd.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,libexec/fwupd/fwupdtool," \ + ${TEMPLATE} > ${ROOT}/dist/fwupdtool.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,bin/fwupdmgr," \ + ${TEMPLATE} > ${ROOT}/dist/fwupdmgr.sh +chmod +x ${ROOT}/dist/*.sh + +#create debugging targets +TARGET=${ROOT}/.vscode +mkdir -p ${TARGET} +if [ -f ${TARGET}/launch.json ]; then + echo "${TARGET}/launch.json already exists, not overwriting" +else + cp ${SOURCE}/launch.json ${TARGET} +fi diff --git a/contrib/vscode/launch.json b/contrib/vscode/launch.json new file mode 100644 index 000000000..ad1aaa0b4 --- /dev/null +++ b/contrib/vscode/launch.json @@ -0,0 +1,68 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "gdbserver (fwupdtool)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/libexec/fwupd/fwupdtool", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "gdbserver (fwupd)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/libexec/fwupd/fwupd", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "gdbserver (fwupdmgr)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/bin/fwupdmgr", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + ] +} diff --git a/contrib/vscode/launcher.sh b/contrib/vscode/launcher.sh new file mode 100755 index 000000000..d324080df --- /dev/null +++ b/contrib/vscode/launcher.sh @@ -0,0 +1,8 @@ +#!/bin/sh +export ROOT=#ROOT# +export FWUPD_LOCALSTATEDIR=${ROOT}/dist +export FWUPD_SYSCONFDIR=${ROOT}/dist/etc +if [ -n "${DEBUG}" ]; then + DEBUG="gdbserver localhost:9091" +fi +${DEBUG} ${ROOT}/dist/#EXECUTABLE# "$@" From 558055c9b71270e45738d175b065f886dc8d357d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 7 Sep 2018 20:36:33 -0500 Subject: [PATCH 010/254] Add a plugin for an upcoming Dell USB-C dock This plugin requires infrastructure introduced in fwupd 1.1.3 and can not be backported to earlier versions of fwupd. It works together with the Synaptics and Thunderbolt plugins to coordinate the proper flashing procedure for devices in this dock. --- contrib/fwupd.spec.in | 1 + plugins/dell-dock/README.md | 26 + plugins/dell-dock/dell-dock.quirk | 127 ++ plugins/dell-dock/fu-dell-dock-common.c | 56 + plugins/dell-dock/fu-dell-dock-common.h | 38 + plugins/dell-dock/fu-dell-dock-hid.c | 376 ++++++ plugins/dell-dock/fu-dell-dock-hid.h | 81 ++ plugins/dell-dock/fu-dell-dock-hub.c | 212 ++++ plugins/dell-dock/fu-dell-dock-hub.h | 32 + plugins/dell-dock/fu-dell-dock-i2c-ec.c | 906 ++++++++++++++ plugins/dell-dock/fu-dell-dock-i2c-ec.h | 51 + plugins/dell-dock/fu-dell-dock-i2c-mst.c | 1066 +++++++++++++++++ plugins/dell-dock/fu-dell-dock-i2c-mst.h | 32 + plugins/dell-dock/fu-dell-dock-status.c | 155 +++ plugins/dell-dock/fu-dell-dock-status.h | 32 + plugins/dell-dock/fu-plugin-dell-dock.c | 286 +++++ plugins/dell-dock/meson.build | 29 + plugins/meson.build | 1 + plugins/synapticsmst/fu-plugin-synapticsmst.c | 3 + plugins/synapticsmst/synapticsmst.quirk | 4 + 20 files changed, 3514 insertions(+) create mode 100644 plugins/dell-dock/README.md create mode 100644 plugins/dell-dock/dell-dock.quirk create mode 100644 plugins/dell-dock/fu-dell-dock-common.c create mode 100644 plugins/dell-dock/fu-dell-dock-common.h create mode 100644 plugins/dell-dock/fu-dell-dock-hid.c create mode 100644 plugins/dell-dock/fu-dell-dock-hid.h create mode 100644 plugins/dell-dock/fu-dell-dock-hub.c create mode 100644 plugins/dell-dock/fu-dell-dock-hub.h create mode 100644 plugins/dell-dock/fu-dell-dock-i2c-ec.c create mode 100644 plugins/dell-dock/fu-dell-dock-i2c-ec.h create mode 100644 plugins/dell-dock/fu-dell-dock-i2c-mst.c create mode 100644 plugins/dell-dock/fu-dell-dock-i2c-mst.h create mode 100644 plugins/dell-dock/fu-dell-dock-status.c create mode 100644 plugins/dell-dock/fu-dell-dock-status.h create mode 100644 plugins/dell-dock/fu-plugin-dell-dock.c create mode 100644 plugins/dell-dock/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 8256d579f..6cef89193 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -259,6 +259,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_dell.so %{_libdir}/fwupd-plugins-3/libfu_plugin_dell_esrt.so %endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_dell_dock.so %{_libdir}/fwupd-plugins-3/libfu_plugin_dfu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ebitdo.so %{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md new file mode 100644 index 000000000..101ba4332 --- /dev/null +++ b/plugins/dell-dock/README.md @@ -0,0 +1,26 @@ +Dell USB-C Dock +========= + +### Dell System +Unlike previous Dell USB-C devices, a Dell system is not needed for updating. + +### Components +The device contains components the following directly updatable components: +* USB hubs +* MST controller +* Thunderbolt controller +* Embedded controller + +This plugin is used to perform the update on the USB hubs as well as the Dell +Embedded controller. The USB hubs are updated directly over a USB HID endpoint +while the embedded controller is updated using an I2C over HID interface. + +The fwupd thunderbolt plugin is used for updating the Titan Ridge controller. + +The MST controller is updated through either the DP Aux interface +(SynapticsMST plugin) or I2C over HID interface provided by this plugin. + +## Device topology +When this plugin is used, devices present in other plugins may be shown in +the topology of this dock. This is intentional as this plugin works together +with those plugins to manage the flashing of all components. diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk new file mode 100644 index 000000000..345eb30ab --- /dev/null +++ b/plugins/dell-dock/dell-dock.quirk @@ -0,0 +1,127 @@ +# +# Copyright (C) 2018 Dell Inc. +# All rights reserved. +# +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. +# +# This file is provided under a dual MIT/LGPLv2 license. When using or +# redistributing this file, you may do so under either license. +# Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. +# +# SPDX-License-Identifier: LGPL-2.1+ OR MIT +# + +[DellDockUnlockTargets] +synapticsmst = 9 + +# Used to make plugin probe the devices +[DeviceInstanceId=USB\VID_413C&PID_B06F] +Name = Unprobed Dell accessory endpoint +Plugin = dell_dock +[DeviceInstanceId=USB\VID_413C&PID_B06E] +Name = Unprobed Dell accessory endpoint +Plugin = dell_dock + +# USB hub1 +[DeviceInstanceId=USB\VID_413C&PID_B06F&hub] +Name = RTS5413 in Dell dock +Summary = USB 3.1 Generation 1 Hub +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +Plugin = dell_dock +Vendor = Dell Inc +Icon = dock-usb +FirmwareSizeMin = 0x10000 +FirmwareSizeMax = 0x10000 +Flags = require-ac,updatable +DellDockUnlockTarget = 8 +DellDockBlobMajorOffset = 0x7F6E +DellDockBlobMinorOffset = 0x7F6F +InstallDuration = 14 + +# USB hub2 +[DeviceInstanceId=USB\VID_413C&PID_B06E&hub] +Name = RTS5487 in Dell dock +Summary = USB 3.1 Generation 2 Hub +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +Vendor = Dell Inc +Plugin = dell_dock +Icon = dock-usb +FirmwareSizeMin = 0x10000 +FirmwareSizeMax = 0x10000 +Flags = require-ac,updatable,has-bridge +DellDockUnlockTarget = 7 +DellDockBlobMajorOffset = 0x7F52 +DellDockBlobMinorOffset = 0x7F53 +InstallDuration = 3 + +# Embedded Controller +# Name is intentionally not set (it's queried by dock) +# TODO: Bump minimum size when raising DellDockBoardMin +[Guid=USB\VID_413C&PID_B06E&hub&embedded] +Name = Dell dock +Summary = High performance dock +Plugin = dell_dock +Vendor = Dell Inc +Icon = dock-usb +FirmwareSizeMin = 0x1C000 +FirmwareSizeMax = 0x20000 +Flags = require-ac +Children = FuDellDockStatus|USB\VID_413C&PID_B06E&hub&status,FuDellDockMst|MST-panamera-vmm5331-259 +DellDockUnlockTarget = 1 +DellDockBoardMin = 2 +DellDockVersionLowest = 00.00.00.09 +DellDockBlobVersionOffset = 0x1AFC0 +InstallDuration = 60 + +# Representation of overall dock update +[DeviceInstanceId=USB\VID_413C&PID_B06E&hub&status] +Name = Package level of Dell dock +Summary = A representation of dock update status +Plugin = dell_dock +Vendor = Dell Inc +Flags = updatable +FirmwareSizeMin = 24 +FirmwareSizeMax = 24 +InstallDuration = 5 +DellDockBlobVersionOffset = 0x14 + +# MST Hub +[Guid=MST-panamera-vmm5331-259] +Name = VMM5331 in Dell dock +Summary = Multi Stream Transport controller +Vendor = Dell Inc +Plugin = synapticsmst +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +Flags = skip-restart,require-ac +FirmwareSizeMin=524288 +FirmwareSizeMax=524288 +DellDockUnlockTarget = 9 +InstallDuration = 95 +DellDockInstallDurationI2C=360 +DellDockBlobMajorOffset = 0x06F0 +DellDockBlobMinorOffset = 0x06F1 +DellDockBlobBuildOffset = 0x06F2 + +# Thunderbolt controller +[Guid=TBT-00d4b070] +Name = Thunderbolt controller in Dell dock +Summary = Thunderbolt controller +Vendor = Dell Inc +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +FirmwareSizeMin=0x40000 +FirmwareSizeMax=0x80000 +Flags = require-ac +InstallDuration = 22 + +# Thunderbolt controller (old ID) +# TODO: This should be dropped when DellDockBoardMin is 3+ +[Guid=TBT-00d40012] +Name = Thunderbolt controller in Dell dock +Summary = Thunderbolt controller +Vendor = Dell Inc +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +FirmwareSizeMin=0x40000 +FirmwareSizeMax=0x80000 +Flags = require-ac,ignore-validation diff --git a/plugins/dell-dock/fu-dell-dock-common.c b/plugins/dell-dock/fu-dell-dock-common.c new file mode 100644 index 000000000..d56ac15bb --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-common.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include "fu-dell-dock-common.h" +#include "fu-device-locker.h" +#include "fu-dell-dock-i2c-ec.h" + +gboolean +fu_dell_dock_set_power (FuDevice *device, guint8 target, + gboolean enabled, GError **error) +{ + FuDevice *parent; + g_autoptr(FuDeviceLocker) locker = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + + parent = FU_IS_DELL_DOCK_EC (device) ? device : fu_device_get_parent (device); + + if (parent == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Couldn't find parent for %s", + fu_device_get_name (device)); + return FALSE; + } + + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + + return fu_dell_dock_ec_modify_lock (parent, target, enabled, error); +} + +void +fu_dell_dock_will_replug (FuDevice *device) +{ + g_return_if_fail (FU_IS_DEVICE (device)); + + g_debug ("Activated %ds replug delay for %s", + REPLUG_TIMEOUT, fu_device_get_name (device)); + fu_device_set_remove_delay (device, REPLUG_TIMEOUT * 1000); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); +} diff --git a/plugins/dell-dock/fu-dell-dock-common.h b/plugins/dell-dock/fu-dell-dock-common.h new file mode 100644 index 000000000..66560b72c --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-common.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#ifndef __FU_DELL_DOCK_COMMON_H +#define __FU_DELL_DOCK_COMMON_H + +#include "config.h" + +#include "fu-device.h" +#include "fu-dell-dock-i2c-ec.h" +#include "fu-dell-dock-i2c-mst.h" +#include "fu-dell-dock-hub.h" +#include "fu-dell-dock-hid.h" +#include "fu-dell-dock-status.h" + +#define DELL_DOCK_EC_GUID "USB\\VID_413C&PID_B06E&hub&embedded" +#define DELL_DOCK_TBT_GUID "TBT-00d4b070" +#define REPLUG_TIMEOUT 60 /* s */ + +gboolean fu_dell_dock_set_power (FuDevice *device, + guint8 target, + gboolean enabled, + GError **error); +void fu_dell_dock_will_replug (FuDevice *device); + +#endif /* __FU_DELL_DOCK_COMMON_H */ diff --git a/plugins/dell-dock/fu-dell-dock-hid.c b/plugins/dell-dock/fu-dell-dock-hid.c new file mode 100644 index 000000000..1dff057af --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-hid.c @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fu-usb-device.h" +#include "fwupd-error.h" + +#include "fu-dell-dock-hid.h" + +#define HIDI2C_MAX_REGISTER 4 +#define HID_MAX_RETRIES 5 +#define HIDI2C_TRANSACTION_TIMEOUT 2000 + +#define HUB_CMD_READ_DATA 0xC0 +#define HUB_CMD_WRITE_DATA 0x40 +#define HUB_EXT_READ_STATUS 0x09 +#define HUB_EXT_MCUMODIFYCLOCK 0x06 +#define HUB_EXT_I2C_WRITE 0xC6 +#define HUB_EXT_WRITEFLASH 0xC8 +#define HUB_EXT_I2C_READ 0xD6 +#define HUB_EXT_VERIFYUPDATE 0xD9 +#define HUB_EXT_ERASEBANK 0xE8 + +typedef struct __attribute__ ((packed)) { + guint8 cmd; + guint8 ext; + union { + guint32 dwregaddr; + struct { + guint8 cmd_data0; + guint8 cmd_data1; + guint8 cmd_data2; + guint8 cmd_data3; + }; + }; + guint16 bufferlen; + FuHIDI2CParameters parameters; + guint8 extended_cmdarea[53]; + guint8 data[192]; +} FuHIDCmdBuffer; + +static gboolean +fu_dell_dock_hid_set_report (FuDevice *self, + guint8 *outbuffer, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gboolean ret; + gsize actual_len = 0; + for (gint i = 1; i <= HID_MAX_RETRIES; i++) { + g_autoptr(GError) error_local = NULL; + ret = g_usb_device_control_transfer ( + usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, HID_REPORT_SET, 0x0200, + 0x0000, outbuffer, 192, &actual_len, + HIDI2C_TRANSACTION_TIMEOUT, NULL, &error_local); + if (ret) + break; + if (i == HID_MAX_RETRIES || + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } else { + g_debug ("attempt %d/%d: set control transfer failed: %s", + i, HID_MAX_RETRIES, + error_local->message); + sleep (1); + } + } + if (actual_len != 192) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_hid_get_report (FuDevice *self, + guint8 *inbuffer, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gboolean ret; + gsize actual_len = 0; + for (gint i = 1; i <= HID_MAX_RETRIES; i++) { + g_autoptr(GError) error_local = NULL; + ret = g_usb_device_control_transfer ( + usb_device, G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, HID_REPORT_GET, 0x0100, + 0x0000, inbuffer, 192, &actual_len, + HIDI2C_TRANSACTION_TIMEOUT, NULL, &error_local); + if (ret) + break; + if (i == HID_MAX_RETRIES || + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } else { + g_debug ("attempt %d/%d: get control transfer failed: %s", + i, HID_MAX_RETRIES, + error_local->message); + } + } + if (actual_len != 192) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_get_hub_version (FuDevice *self, + GError **error) +{ + g_autofree gchar *version = NULL; + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, + .ext = HUB_EXT_READ_STATUS, + .cmd_data0 = 0, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (12), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to query hub version: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to query hub version: "); + return FALSE; + } + + version = g_strdup_printf ("%02x.%02x", + cmd_buffer.data[10], + cmd_buffer.data[11]); + fu_device_set_version (self, version); + + return TRUE; +} + +gboolean +fu_dell_dock_hid_raise_mcu_clock (FuDevice *self, + gboolean enable, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_MCUMODIFYCLOCK, + .cmd_data0 = (guint8) enable, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = 0, + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, + "failed to set mcu clock to %d: ", + enable); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_get_ec_status (FuDevice *self, + guint8 *status1, + guint8 *status2, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_READ_STATUS, + .cmd_data0 = 0, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (27), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to get EC status: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get EC status: "); + return FALSE; + } + + *status1 = cmd_buffer.data[25]; + *status2 = cmd_buffer.data[26]; + + return TRUE; +} + +gboolean +fu_dell_dock_hid_erase_bank (FuDevice *self, guint8 idx, GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_ERASEBANK, + .cmd_data0 = 0, + .cmd_data1 = idx, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = 0, + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to erase bank: "); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_write_flash (FuDevice *self, + guint32 dwAddr, + const guint8 *input, + gsize write_size, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_WRITEFLASH, + .dwregaddr = GUINT32_TO_LE (dwAddr), + .bufferlen = GUINT16_TO_LE (write_size), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + g_return_val_if_fail (write_size <= HIDI2C_MAX_WRITE, FALSE); + + memcpy (cmd_buffer.data, input, write_size); + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error ( + error, "failed to write %" G_GSIZE_FORMAT " flash to %x: ", + write_size, dwAddr); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_verify_update (FuDevice *self, + gboolean *result, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_VERIFYUPDATE, + .cmd_data0 = 1, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (1), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to verify update: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to verify update: "); + return FALSE; + } + *result = cmd_buffer.data[0]; + + return TRUE; +} + +gboolean +fu_dell_dock_hid_i2c_write (FuDevice *self, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_I2C_WRITE, + .dwregaddr = 0, + .bufferlen = GUINT16_TO_LE (write_size), + .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .regaddrlen = 0, + .i2cspeed = parameters->i2cspeed | 0x80}, + .extended_cmdarea[0 ... 52] = 0, + }; + + g_return_val_if_fail (write_size <= HIDI2C_MAX_WRITE, FALSE); + + memcpy (cmd_buffer.data, input, write_size); + + return fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error); +} + +gboolean +fu_dell_dock_hid_i2c_read (FuDevice *self, + guint32 cmd, + gsize read_size, + GBytes **bytes, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_I2C_READ, + .dwregaddr = GUINT32_TO_LE (cmd), + .bufferlen = GUINT16_TO_LE (read_size), + .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .regaddrlen = parameters->regaddrlen, + .i2cspeed = parameters->i2cspeed | 0x80}, + .extended_cmdarea[0 ... 52] = 0, + .data[0 ... 191] = 0, + }; + + g_return_val_if_fail (read_size <= HIDI2C_MAX_READ, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (parameters->regaddrlen < HIDI2C_MAX_REGISTER, FALSE); + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) + return FALSE; + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) + return FALSE; + + *bytes = g_bytes_new (cmd_buffer.data, read_size); + + return TRUE; +} diff --git a/plugins/dell-dock/fu-dell-dock-hid.h b/plugins/dell-dock/fu-dell-dock-hid.h new file mode 100644 index 000000000..c732f5992 --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-hid.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#ifndef __FU_DELL_DOCK_HID_H +#define __FU_DELL_DOCK_HID_H + +#include "config.h" + +#include + +#include "fu-device.h" + +typedef struct __attribute__ ((packed)) { + guint8 i2cslaveaddr; + guint8 regaddrlen; + guint8 i2cspeed; +} FuHIDI2CParameters; + +typedef enum { + I2C_SPEED_250K, + I2C_SPEED_400K, + I2C_SPEED_800K, + /* */ + I2C_SPEED_LAST, +} BridgedI2CSpeed; + +#define HIDI2C_MAX_READ 192 +#define HIDI2C_MAX_WRITE 128 + +gboolean fu_dell_dock_hid_i2c_write (FuDevice *self, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error); +gboolean fu_dell_dock_hid_i2c_read (FuDevice *self, + guint32 cmd, + gsize read_size, + GBytes **bytes, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_get_hub_version (FuDevice *self, + GError **error); + +gboolean fu_dell_dock_hid_raise_mcu_clock (FuDevice *self, + gboolean enable, + GError **error); + +gboolean fu_dell_dock_hid_get_ec_status (FuDevice *self, + guint8 *status1, + guint8 *status2, + GError **error); + +gboolean fu_dell_dock_hid_erase_bank (FuDevice *self, + guint8 idx, + GError **error); + +gboolean fu_dell_dock_hid_write_flash (FuDevice *self, + guint32 addr, + const guint8 *input, + gsize write_size, + GError **error); + +gboolean fu_dell_dock_hid_verify_update (FuDevice *self, + gboolean *result, + GError **error); + +#endif /* __FU_DELL_DOCK_HID_H */ diff --git a/plugins/dell-dock/fu-dell-dock-hub.c b/plugins/dell-dock/fu-dell-dock-hub.c new file mode 100644 index 000000000..4966de37b --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-hub.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fu-usb-device.h" +#include "fwupd-error.h" + +#include "fu-dell-dock-common.h" + +struct _FuDellDockHub { + FuUsbDevice parent_instance; + guint8 unlock_target; + guint64 blob_major_offset; + guint64 blob_minor_offset; +}; + +G_DEFINE_TYPE (FuDellDockHub, fu_dell_dock_hub, FU_TYPE_USB_DEVICE) + +static gboolean +fu_dell_dock_hub_probe (FuDevice *device, GError **error) +{ + g_autofree gchar *guid = NULL; + + guid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&hub", + (guint) fu_usb_device_get_vid (FU_USB_DEVICE (device)), + (guint) fu_usb_device_get_pid (FU_USB_DEVICE (device))); + + fu_device_set_logical_id (device, "hub"); + fu_device_add_guid (device, guid); + + return TRUE; +} + +static gboolean +fu_dell_dock_hub_write_fw (FuDevice *device, + GBytes *blob_fw, + GError **error) +{ + FuDellDockHub *self = FU_DELL_DOCK_HUB (device); + gsize fw_size = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &fw_size); + gsize write_size = + (fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size; + gsize nwritten = 0; + guint32 address = 0; + gboolean result = FALSE; + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + dynamic_version = g_strdup_printf ("%02x.%02x", + data[self->blob_major_offset], + data[self->blob_minor_offset]); + g_debug ("Writing firmware version %s", dynamic_version); + + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + + if (!fu_dell_dock_hid_raise_mcu_clock (device, TRUE, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_dell_dock_hid_erase_bank (device, 1, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + do { + /* last packet */ + if (fw_size - nwritten < write_size) + write_size = fw_size - nwritten; + + if (!fu_dell_dock_hid_write_flash (device, address, data, + write_size, error)) + return FALSE; + nwritten += write_size; + data += write_size; + address += write_size; + fu_device_set_progress_full (device, nwritten, fw_size); + } while (nwritten < fw_size); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_dell_dock_hid_verify_update (device, &result, error)) + return FALSE; + if (!result) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to verify the update"); + return FALSE; + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + + return TRUE; +} + +static gboolean +fu_dell_dock_hub_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockHub *self = FU_DELL_DOCK_HUB (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockBlobMajorOffset") == 0) { + self->blob_major_offset = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobMinorOffset") == 0) { + self->blob_minor_offset = fu_common_strtoull (value); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static gboolean +fu_dell_dock_hub_open (FuUsbDevice *fu_usb_device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (fu_usb_device); + + /* open device and clear status */ + if (!g_usb_device_claim_interface ( + usb_device, 0, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) { + g_prefix_error (error, "failed to claim HID interface: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_hub_close (FuUsbDevice *fu_usb_device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (fu_usb_device); + + if (!g_usb_device_release_interface ( + usb_device, 0, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + + return TRUE; +} + +static void +fu_dell_dock_hub_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_dell_dock_hub_parent_class)->finalize (object); +} + +static void +fu_dell_dock_hub_init (FuDellDockHub *self) +{ +} + +static void +fu_dell_dock_hub_class_init (FuDellDockHubClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_hub_finalize; + klass_usb_device->open = fu_dell_dock_hub_open; + klass_usb_device->close = fu_dell_dock_hub_close; + klass_device->setup = fu_dell_dock_hid_get_hub_version; + klass_device->probe = fu_dell_dock_hub_probe; + klass_device->write_firmware = fu_dell_dock_hub_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_hub_set_quirk_kv; +} + +FuDellDockHub * +fu_dell_dock_hub_new (FuUsbDevice *device) +{ + FuDellDockHub *self = g_object_new (FU_TYPE_DELL_DOCK_HUB, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff --git a/plugins/dell-dock/fu-dell-dock-hub.h b/plugins/dell-dock/fu-dell-dock-hub.h new file mode 100644 index 000000000..a002672c3 --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-hub.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#ifndef __FU_DELL_DOCK_HUB_H +#define __FU_DELL_DOCK_HUB_H + +#include "config.h" + +#include "fu-usb-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_HUB (fu_dell_dock_hub_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockHub, fu_dell_dock_hub, FU, DELL_DOCK_HUB, FuUsbDevice) + +FuDellDockHub *fu_dell_dock_hub_new (FuUsbDevice *device); + +G_END_DECLS + +#endif /* __FU_DELL_DOCK_HUB_H */ diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c new file mode 100644 index 000000000..4f4a5c833 --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -0,0 +1,906 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include +#include + +#include "fu-usb-device.h" +#include "fwupd-error.h" + +#include "fu-dell-dock-common.h" + +#define I2C_EC_ADDRESS 0xec + +#define EC_CMD_SET_DOCK_PKG 0x01 +#define EC_CMD_GET_DOCK_INFO 0x02 +#define EC_CMD_GET_DOCK_DATA 0x03 +#define EC_CMD_GET_DOCK_TYPE 0x05 +#define EC_CMD_MODIFY_LOCK 0x0a +#define EC_CMD_RESET 0x0b +#define EC_CMD_REBOOT 0x0c +#define EC_GET_FW_UPDATE_STATUS 0x0f + +#define EXPECTED_DOCK_INFO_SIZE 0xb7 +#define EXPECTED_DOCK_TYPE 0x04 + +typedef enum { + FW_UPDATE_IN_PROGRESS, + FW_UPDATE_COMPLETE, +} FuDellDockECFWUpdateStatus; + +const FuHIDI2CParameters ec_base_settings = { + .i2cslaveaddr = I2C_EC_ADDRESS, + .regaddrlen = 1, + .i2cspeed = I2C_SPEED_250K, +}; + +typedef enum { + LOCATION_BASE, + LOCATION_MODULE, +} FuDellDockLocationEnum; + +typedef enum { + FU_DELL_DOCK_DEVICETYPE_MAIN_EC = 0, + FU_DELL_DOCK_DEVICETYPE_HUB = 3, + FU_DELL_DOCK_DEVICETYPE_MST = 4, + FU_DELL_DOCK_DEVICETYPE_TBT = 5, +} FuDellDockDeviceTypeEnum; + +typedef enum { + SUBTYPE_GEN2, + SUBTYPE_GEN1, +} FuDellDockHubSubTypeEnum; + +typedef struct __attribute__ ((packed)) { + guint8 total_devices; + guint8 first_index; + guint8 last_index; +} FuDellDockDockInfoHeader; + +typedef struct __attribute__ ((packed)) { + guint8 location; + guint8 device_type; + guint8 sub_type; + guint8 arg; + guint8 instance; +} FuDellDockEcAddrMap; + +typedef struct __attribute__ ((packed)) { + FuDellDockEcAddrMap ec_addr_map; + union { + guint32 version_32; + guint8 version_8[4]; + } version; +} FuDellDockEcQueryEntry; + +typedef enum { + MODULE_TYPE_SINGLE = 1, + MODULE_TYPE_DUAL, + MODULE_TYPE_TBT, +} FuDellDockDockModule; + +typedef struct __attribute__ ((packed)) { + guint8 dock_configuration; + guint8 dock_type; + guint16 power_supply_wattage; + guint16 module_type; + guint16 board_id; + guint16 port0_dock_status; + guint16 port1_dock_status; + guint32 dock_firmware_pkg_ver; + guint64 module_serial; + guint64 original_module_serial; + gchar service_tag[7]; + gchar marketing_name[64]; +} FuDellDockDockDataStructure; + +typedef struct __attribute__ ((packed)) { + guint32 ec_version; + guint32 mst_version; + guint32 hub1_version; + guint32 hub2_version; + guint32 tbt_version; + guint32 pkg_version; +} FuDellDockDockPackageFWVersion; + +struct _FuDellDockEc { + FuDevice parent_instance; + FuDellDockDockDataStructure *data; + FuDellDockDockPackageFWVersion *raw_versions; + gchar *ec_version; + gchar *mst_version; + gchar *tbt_version; + FuDevice *symbiote; + guint8 unlock_target; + guint8 board_min; + gchar *ec_minimum_version; + guint64 blob_version_offset; +}; + +G_DEFINE_TYPE (FuDellDockEc, fu_dell_dock_ec, FU_TYPE_DEVICE) + +/* Used to root out I2C communication problems */ +static gboolean +fu_dell_dock_test_valid_byte (const guint8 *str, gint index) +{ + if (str[index] == 0x00 || str[index] == 0xff) + return FALSE; + return TRUE; +} + +static void +fu_dell_dock_ec_set_board (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + const gchar *summary = NULL; + g_autofree gchar *board_type_str = NULL; + + board_type_str = g_strdup_printf ("DellDockBoard%u", self->data->board_id); + summary = fu_device_get_metadata (device, board_type_str); + if (summary != NULL) + fu_device_set_summary (device, summary); +} + +FuDevice * +fu_dell_dock_ec_get_symbiote (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + return self->symbiote; +} + +gboolean +fu_dell_dock_ec_has_tbt (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + return self->data->module_type == MODULE_TYPE_TBT; +} + +static const gchar* +fu_dell_dock_devicetype_to_str (guint device_type, guint sub_type) +{ + switch (device_type) { + case FU_DELL_DOCK_DEVICETYPE_MAIN_EC: + return "EC"; + case FU_DELL_DOCK_DEVICETYPE_MST: + return "MST"; + case FU_DELL_DOCK_DEVICETYPE_TBT: + return "Thunderbolt"; + case FU_DELL_DOCK_DEVICETYPE_HUB: + if (sub_type == SUBTYPE_GEN2) + return "USB 3.1 Gen2"; + else if (sub_type == SUBTYPE_GEN1) + return "USB 3.1 Gen1"; + return NULL; + default: + return NULL; + } +} + +static gboolean +fu_dell_dock_ec_read (FuDevice *device, guint32 cmd, gsize length, + GBytes **bytes, GError **error) +{ + /* The first byte of result data will be the size of the return, + hide this from callers */ + guint8 result_length = length + 1; + g_autoptr(GBytes) bytes_local = NULL; + const guint8 *result; + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (self->symbiote != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + + if (!fu_dell_dock_hid_i2c_read (self->symbiote, cmd, result_length, + &bytes_local, &ec_base_settings, error)) { + g_prefix_error (error, "read over HID-I2C failed: "); + return FALSE; + } + result = g_bytes_get_data (bytes_local, NULL); + /* first byte of result should be size of our data */ + if (result[0] != length) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Invalid result data: %d expected %" G_GSIZE_FORMAT, + result[0], length); + return FALSE; + } + *bytes = g_bytes_new (result + 1, length); + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_write (FuDevice *device, gsize length, guint8 *data, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (self->symbiote != NULL, FALSE); + g_return_val_if_fail (length > 1, FALSE); + + if (!fu_dell_dock_hid_i2c_write (self->symbiote, data, length, + &ec_base_settings, error)) { + g_prefix_error (error, "write over HID-I2C failed: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_is_valid_dock (FuDevice *device, GError **error) +{ + g_autoptr(GBytes) data = NULL; + const guint8 *result = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_CMD_GET_DOCK_TYPE, 1, &data, error)) { + g_prefix_error (error, "Failed to query dock type: "); + return FALSE; + } + result = g_bytes_get_data (data, NULL); + + if (result == NULL || *result != EXPECTED_DOCK_TYPE) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "No valid dock was found"); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_dell_dock_ec_get_dock_info (FuDevice *device, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + const FuDellDockDockInfoHeader *header = NULL; + const FuDellDockEcQueryEntry *device_entry = NULL; + const FuDellDockEcAddrMap *map = NULL; + g_autoptr(GBytes) data = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_CMD_GET_DOCK_INFO, + EXPECTED_DOCK_INFO_SIZE, + &data, error)) { + g_prefix_error (error, "Failed to query dock info: "); + return FALSE; + } + if (!g_bytes_get_data (data, NULL)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to read dock info"); + return FALSE; + } + + header = (FuDellDockDockInfoHeader *) g_bytes_get_data (data, NULL); + if (!header) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to parse dock info"); + return FALSE; + } + + /* guard against EC not yet ready and fail init */ + if (header->total_devices == 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, + "No bridge devices detected, dock may be booting up"); + return FALSE; + } + g_debug ("%u devices [%u->%u]", + header->total_devices, + header->first_index, + header->last_index); + device_entry = + (FuDellDockEcQueryEntry *) ((guint8 *) header + sizeof(FuDellDockDockInfoHeader)); + for (guint i = 0; i < header->total_devices; i++) { + const gchar *type_str; + map = &(device_entry[i].ec_addr_map); + type_str = fu_dell_dock_devicetype_to_str (map->device_type, map->sub_type); + if (type_str == NULL) + continue; + g_debug ("#%u: %s in %s (A: %u I: %u)", i, type_str, + (map->location == LOCATION_BASE) ? "Base" : "Module", + map->arg, map->instance); + g_debug ("\tVersion32: %08x\tVersion8: %x %x %x %x", + device_entry[i].version.version_32, + device_entry[i].version.version_8[0], + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + /* BCD but guint32 */ + if (map->device_type == FU_DELL_DOCK_DEVICETYPE_MAIN_EC) { + self->raw_versions->ec_version = device_entry[i].version.version_32; + self->ec_version = g_strdup_printf ( + "%02x.%02x.%02x.%02x", device_entry[i].version.version_8[0], + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + g_debug ("\tParsed version %s", self->ec_version); + fu_device_set_version (self, self->ec_version); + + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_MST) { + self->raw_versions->mst_version = device_entry[i].version.version_32; + /* guard against invalid MST version read from EC */ + if (!fu_dell_dock_test_valid_byte (device_entry[i].version.version_8, 1)) { + g_warning ("[EC Bug] EC read invalid MST version %08x", + device_entry[i].version.version_32); + continue; + } + self->mst_version = g_strdup_printf ("%02x.%02x.%02x", + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + g_debug ("\tParsed version %s", self->mst_version); + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_TBT && fu_dell_dock_ec_has_tbt (device)) { + /* guard against invalid Thunderbolt version read from EC */ + if (!fu_dell_dock_test_valid_byte (device_entry[i].version.version_8, 2)) { + g_warning ("[EC bug] EC read invalid Thunderbolt version %08x", + device_entry[i].version.version_32); + continue; + } + self->raw_versions->tbt_version = device_entry[i].version.version_32; + self->tbt_version = g_strdup_printf ("%02x.%02x", + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + g_debug ("\tParsed version %s", self->tbt_version); + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_HUB) { + g_debug ("\thub subtype: %u", map->sub_type); + if (map->sub_type == SUBTYPE_GEN2) + self->raw_versions->hub2_version = device_entry[i].version.version_32; + else if (map->sub_type == SUBTYPE_GEN1) + self->raw_versions->hub1_version = device_entry[i].version.version_32; + } + } + + /* minimum EC version this code will support */ + if (as_utils_vercmp (self->ec_version, self->ec_minimum_version) < 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "dock containing EC version %s is not supported", + self->ec_version); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_get_dock_data (FuDevice *device, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + g_autoptr(GBytes) data = NULL; + g_autoptr(GString) name = NULL; + gchar service_tag[8] = {0x00}; + const guint8 *result; + gsize length = sizeof(FuDellDockDockDataStructure); + g_autofree gchar *bundled_serial = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_CMD_GET_DOCK_DATA, length, + &data, error)) { + g_prefix_error (error, "Failed to query dock info: "); + return FALSE; + } + result = g_bytes_get_data (data, NULL); + if (result == NULL) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to read dock data"); + return FALSE; + } + if (g_bytes_get_size (data) != length) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Unexpected dock data size %" G_GSIZE_FORMAT, + g_bytes_get_size (data)); + return FALSE; + } + memcpy (self->data, result, length); + + /* guard against EC not yet ready and fail init */ + name = g_string_new (self->data->marketing_name); + if (name->len == 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, + "Invalid name detected, dock may be booting up"); + return FALSE; + } + fu_device_set_name (device, name->str); + + /* set serial number */ + memcpy (service_tag, self->data->service_tag, 7); + bundled_serial = g_strdup_printf ("%s/%08" G_GUINT64_FORMAT, + service_tag, + self->data->module_serial); + fu_device_set_serial (device, bundled_serial); + + /* copy this for being able to send in next commit transaction */ + self->raw_versions->pkg_version = self->data->dock_firmware_pkg_ver; + + /* make sure this hardware spin matches our expecations */ + if (self->data->board_id >= self->board_min) { + fu_dell_dock_ec_set_board (device); + fu_device_set_version (device, self->ec_version); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + g_warning ("This utility does not support this board, disabling updates for %s", + fu_device_get_name (device)); + } + + return TRUE; +} + +static void +fu_dell_dock_ec_to_string (FuDevice *device, GString *str) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + gchar service_tag[8] = {0x00}; + + g_string_append (str, " FuDellDellDockEc:\n"); + g_string_append_printf (str, "\tboard ID: %u\n", + self->data->board_id); + g_string_append_printf (str, "\tpower supply: %uW\n", + self->data->power_supply_wattage); + g_string_append_printf (str, "\tstatus (port0): %x\n", + self->data->port0_dock_status); + g_string_append_printf (str, "\tstatus (port1): %x\n", + self->data->port1_dock_status); + memcpy (service_tag, self->data->service_tag, 7); + g_string_append_printf (str, "\tservice tag: %s\n", + service_tag); + g_string_append_printf (str, "\tconfiguration: %u\n", + self->data->dock_configuration); + g_string_append_printf (str, "\tpackage firmware version: %x\n", + self->data->dock_firmware_pkg_ver); + g_string_append_printf (str, "\tmodule serial #: %08" G_GUINT64_FORMAT "\n", + self->data->module_serial); + g_string_append_printf (str, "\toriginal module serial #: %08" G_GUINT64_FORMAT "\n", + self->data->original_module_serial); + g_string_append_printf (str, "\ttype: %u\n", + self->data->dock_type); + g_string_append_printf (str, "\tmodule type: %x\n", + self->data->module_type); + g_string_append_printf (str, "\tminimum ec: %s\n", + self->ec_minimum_version); +} + +gboolean +fu_dell_dock_ec_modify_lock (FuDevice *device, + guint8 target, + gboolean unlocked, + GError **error) +{ + guint32 cmd; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (target != 0, FALSE); + + cmd = EC_CMD_MODIFY_LOCK | /* cmd */ + 2 << 8 | /* length of data arguments */ + target << 16 | /* device to operate on */ + unlocked << 24; /* unlock/lock */ + + + if (!fu_dell_dock_ec_write (device, 4, (guint8 *) &cmd, error)) { + g_prefix_error (error, "Failed to unlock device %d: ", target); + return FALSE; + } + g_debug ("Modified lock for %d to %d through %s (%s)", + target, unlocked, + fu_device_get_name (device), + fu_device_get_id (device)); + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_reset (FuDevice *device, GError **error) +{ + guint16 cmd = EC_CMD_RESET; + + g_return_val_if_fail (device != NULL, FALSE); + + return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); +} + +gboolean +fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + guint16 cmd = EC_CMD_REBOOT; + + g_return_val_if_fail (device != NULL, FALSE); + + if (fu_device_has_custom_flag (device, "skip-restart")) { + g_debug ("Skipping reboot per quirk request"); + return TRUE; + } + + /* TODO: Drop when bumping minimum EC version to 13+ */ + if (as_utils_vercmp (self->ec_version, "00.00.00.13") < 0) + g_print ("\nEC Reboot API may fail on EC %s. Please manually power cycle dock.\n", + self->ec_version); + g_debug ("Rebooting %s", fu_device_get_name (device)); + + return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); +} + +static gboolean +fu_dell_dock_get_ec_status (FuDevice *device, + FuDellDockECFWUpdateStatus *status_out, + GError **error) +{ + g_autoptr(GBytes) data = NULL; + const guint8 *result = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (status_out != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_GET_FW_UPDATE_STATUS, 1, + &data, error)) { + g_prefix_error (error, "Failed to read FW update status: "); + return FALSE; + } + result = g_bytes_get_data (data, NULL); + + if (!result) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to read FW update status"); + return FALSE; + } + *status_out = *result; + return TRUE; +} + +const gchar* +fu_dell_dock_ec_get_tbt_version (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + return self->tbt_version; +} + +const gchar* +fu_dell_dock_ec_get_mst_version (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + return self->mst_version; +} + +guint32 +fu_dell_dock_ec_get_status_version (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + return self->raw_versions->pkg_version; +} + +gboolean +fu_dell_dock_ec_commit_package (FuDevice *device, GBytes *blob_fw, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + gsize length = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &length); + guint8 payload[length + 2]; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + if (length != sizeof(FuDellDockDockPackageFWVersion)) { + g_set_error (error, G_IO_ERR, G_IO_ERROR_INVALID_DATA, + "Invalid package size %" G_GSIZE_FORMAT, + length); + return FALSE; + } + memcpy (self->raw_versions, data, length); + + g_debug ("Committing (%zu) bytes ", sizeof(FuDellDockDockPackageFWVersion)); + g_debug ("\tec_version: %x", self->raw_versions->ec_version); + g_debug ("\tmst_version: %x", self->raw_versions->mst_version); + g_debug ("\thub1_version: %x", self->raw_versions->hub1_version); + g_debug ("\thub2_version: %x", self->raw_versions->hub2_version); + g_debug ("\ttbt_version: %x", self->raw_versions->tbt_version); + g_debug ("\tpkg_version: %x", self->raw_versions->pkg_version); + + /* TODO: Drop when updating minimum EC to 11+ */ + if (as_utils_vercmp (self->ec_version, "00.00.00.11") < 0) { + g_debug ("EC %s doesn't support package version, ignoring", + self->ec_version); + return TRUE; + } + + payload [0] = EC_CMD_SET_DOCK_PKG; + payload [1] = length; + memcpy (payload + 2, data, length); + + if (!fu_dell_dock_ec_write (device, length + 2, payload, error)) { + g_prefix_error (error, "Failed to query dock info: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_write_fw (FuDevice *device, GBytes *blob_fw, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + FuDellDockECFWUpdateStatus status = FW_UPDATE_IN_PROGRESS; + guint8 progress1 = 0, progress0 = 0; + gsize fw_size = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &fw_size); + gsize write_size = + (fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size; + gsize nwritten = 0; + guint32 address = 0 | 0xff << 24; + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + dynamic_version = g_strndup ((gchar *) data + self->blob_version_offset, 11); + g_debug ("Writing firmware version %s", dynamic_version); + + if (!fu_dell_dock_ec_modify_lock (device, self->unlock_target, TRUE, error)) + return FALSE; + + if (!fu_dell_dock_hid_raise_mcu_clock (self->symbiote, TRUE, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_dell_dock_hid_erase_bank (self->symbiote, 0xff, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + do { + /* last packet */ + if (fw_size - nwritten < write_size) + write_size = fw_size - nwritten; + + if (!fu_dell_dock_hid_write_flash (self->symbiote, address, data, + write_size, error)) { + g_prefix_error (error, "write over HID failed: "); + return FALSE; + } + fu_device_set_progress_full (device, nwritten, fw_size); + nwritten += write_size; + data += write_size; + address += write_size; + } while (nwritten < fw_size); + + if (!fu_dell_dock_hid_raise_mcu_clock (self->symbiote, FALSE, error)) + return FALSE; + + if (fu_device_has_custom_flag (device, "skip-restart")) { + g_debug ("Skipping EC reset per quirk request"); + return TRUE; + } + + if (!fu_dell_dock_ec_reset (device, error)) + return FALSE; + + /* notify daemon that this device will need to replug */ + fu_dell_dock_will_replug (device); + + /* poll for completion status */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + while (status != FW_UPDATE_COMPLETE) { + g_autoptr(GError) error_local = NULL; + + if (!fu_dell_dock_hid_get_ec_status (self->symbiote, &progress1, + &progress0, error)) { + g_prefix_error (error, "Failed to read scratch: "); + return FALSE; + } + g_debug ("Read %u and %u from scratch", progress1, progress0); + if (progress0 > 100) + progress0 = 100; + fu_device_set_progress_full (device, progress0, 100); + + /* This is expected to fail until update is done + * TODO: After can guarantee EC version that reports status byte + * don't call this until progress0 is 100 + */ + if (!fu_dell_dock_get_ec_status (device, &status, + &error_local)) { + g_debug ("Flash EC Received result: %s (status %u)", + error_local->message, status); + return TRUE; + } + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockBoardMin") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->board_min = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockBoardMin"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockVersionLowest") == 0) { + self->ec_minimum_version = g_strdup (value); + return TRUE; + } + if (g_str_has_prefix (key, "DellDockBoard")) { + fu_device_set_metadata (device, key, value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobVersionOffset") == 0) { + self->blob_version_offset = fu_common_strtoull (value); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static gboolean +fu_dell_dock_ec_probe (FuDevice *device, GError **error) +{ + /* this will trigger setting up all the quirks */ + fu_device_add_guid (device, DELL_DOCK_EC_GUID); + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_query (FuDevice *device, GError **error) +{ + if (!fu_dell_dock_ec_get_dock_data (device, error)) + return FALSE; + + return fu_dell_dock_ec_get_dock_info (device, error); +} + +static gboolean +fu_dell_dock_ec_setup (FuDevice *device, GError **error) +{ + g_autoptr(GError) error_local = NULL; + GPtrArray *children; + + /* if query looks bad, wait a few seconds and retry */ + if (!fu_dell_dock_ec_query (device, &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID)) { + g_warning ("%s", error_local->message); + g_usleep (2 * G_USEC_PER_SEC); + if (!fu_dell_dock_ec_query (device, error)) + return FALSE; + } else { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + } + + /* call setup on all the children we produced */ + children = fu_device_get_children (device); + for (guint i=0 ; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + g_autoptr(FuDeviceLocker) locker = NULL; + g_debug ("setup %s", + fu_device_get_name (child)); + locker = fu_device_locker_new (child, error); + if (locker == NULL) + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_open (FuDevice *device, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + if (!fu_device_open (self->symbiote, error)) + return FALSE; + + return fu_dell_dock_is_valid_dock (device, error); +} + +static gboolean +fu_dell_dock_ec_close (FuDevice *device, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + return fu_device_close (self->symbiote, error); +} + +static void +fu_dell_dock_ec_finalize (GObject *object) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (object); + g_object_unref (self->symbiote); + g_free (self->ec_version); + g_free (self->mst_version); + g_free (self->tbt_version); + g_free (self->data); + g_free (self->raw_versions); + g_free (self->ec_minimum_version); + G_OBJECT_CLASS (fu_dell_dock_ec_parent_class)->finalize (object); +} + +static void +fu_dell_dock_ec_init (FuDellDockEc *self) +{ + self->data = g_new0 (FuDellDockDockDataStructure, 1); + self->raw_versions = g_new0 (FuDellDockDockPackageFWVersion, 1); +} + +static void +fu_dell_dock_ec_class_init (FuDellDockEcClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_ec_finalize; + klass_device->to_string = fu_dell_dock_ec_to_string; + klass_device->probe = fu_dell_dock_ec_probe; + klass_device->setup = fu_dell_dock_ec_setup; + klass_device->open = fu_dell_dock_ec_open; + klass_device->close = fu_dell_dock_ec_close; + klass_device->write_firmware = fu_dell_dock_ec_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_ec_set_quirk_kv; +} + +FuDellDockEc * +fu_dell_dock_ec_new (FuDevice *symbiote) +{ + FuDellDockEc *self = NULL; + + self = g_object_new (FU_TYPE_DELL_DOCK_EC, NULL); + self->symbiote = g_object_ref (symbiote); + fu_device_set_physical_id (FU_DEVICE (self), + fu_device_get_physical_id (self->symbiote)); + fu_device_set_logical_id (FU_DEVICE (self), "ec"); + + return self; +} diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.h b/plugins/dell-dock/fu-dell-dock-i2c-ec.h new file mode 100644 index 000000000..a76bcff52 --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#ifndef __FU_DELL_DOCK_EC_H +#define __FU_DELL_DOCK_EC_H + +#include "config.h" + +#include + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_EC (fu_dell_dock_ec_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockEc, fu_dell_dock_ec, FU, DELL_DOCK_EC, FuDevice) + +FuDellDockEc *fu_dell_dock_ec_new (FuDevice *symbiote); + +G_END_DECLS + +gboolean fu_dell_dock_ec_has_tbt (FuDevice *device); +gboolean fu_dell_dock_ec_modify_lock (FuDevice *self, + guint8 target, + gboolean unlocked, + GError **error); + +gboolean fu_dell_dock_ec_reboot_dock (FuDevice *device, + GError **error); + +const gchar *fu_dell_dock_ec_get_mst_version (FuDevice *device); +const gchar *fu_dell_dock_ec_get_tbt_version (FuDevice *device); +guint32 fu_dell_dock_ec_get_status_version (FuDevice *device); +gboolean fu_dell_dock_ec_commit_package (FuDevice *device, + GBytes *blob_fw, + GError **error); +FuDevice *fu_dell_dock_ec_get_symbiote (FuDevice *device); + +#endif /* __FU_DELL_DOCK_EC_H */ diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c new file mode 100644 index 000000000..e92cc603a --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -0,0 +1,1066 @@ +/* + * Copyright (C) 2018 Synaptics + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" + +#include "fu-dell-dock-common.h" + +#define I2C_MST_ADDRESS 0x72 + +/* MST registers */ +#define MST_RC_TRIGGER_ADDR 0x2000fc +#define MST_CORE_MCU_BOOTLOADER_STS 0x20010c +#define MST_RC_COMMAND_ADDR 0x200110 +#define MST_RC_OFFSET_ADDR 0x200114 +#define MST_RC_LENGTH_ADDR 0x200118 +#define MST_RC_DATA_ADDR 0x200120 +#define MST_CORE_MCU_FW_VERSION 0x200160 +#define MST_REG_QUAD_DISABLE 0x200fc0 +#define MST_REG_HDCP22_DISABLE 0x200f90 + +/* MST remote control commands */ +#define MST_CMD_ENABLE_REMOTE_CONTROL 0x1 +#define MST_CMD_DISABLE_REMOTE_CONTROL 0x2 +#define MST_CMD_CHECKSUM 0x11 +#define MST_CMD_ERASE_FLASH 0x14 +#define MST_CMD_WRITE_FLASH 0x20 +#define MST_CMD_READ_FLASH 0x30 +#define MST_CMD_WRITE_MEMORY 0x21 +#define MST_CMD_READ_MEMORY 0x31 + +/* Arguments related to flashing */ +#define FLASH_SECTOR_ERASE_4K 0x1000 +#define FLASH_SECTOR_ERASE_32K 0x2000 +#define FLASH_SECTOR_ERASE_64K 0x3000 +#define EEPROM_TAG_OFFSET 0x1fff0 +#define EEPROM_BANK_OFFSET 0x20000 +#define EEPROM_ESM_OFFSET 0x40000 + +/* Flash offsets */ +#define MST_BOARDID_OFFSET 0x10e + +/* Remote control offsets */ +#define MST_CHIPID_OFFSET 0x1500 + +/* magic triggers */ +#define MST_TRIGGER_WRITE 0xf2 +#define MST_TRIGGER_REBOOT 0xf5 + +/* IDs used in DELL_DOCK */ +#define EXPECTED_CHIPID 0x5331 + +/* firmware file offsets */ +#define MST_BLOB_VERSION_OFFSET 0x06F0 + +typedef enum { + Bank0, + Bank1, + ESM, +} MSTBank; + +typedef struct { + guint start; + guint length; +} MSTBankAttributes; + +const MSTBankAttributes bank0_attributes = { + .start = 0, + .length = EEPROM_BANK_OFFSET, +}; + +const MSTBankAttributes bank1_attributes = { + .start = EEPROM_BANK_OFFSET, + .length = EEPROM_BANK_OFFSET, +}; + +const MSTBankAttributes esm_attributes = { + .start = EEPROM_ESM_OFFSET, + .length = 0x3ffff +}; + +FuHIDI2CParameters mst_base_settings = { + .i2cslaveaddr = I2C_MST_ADDRESS, + .regaddrlen = 0, + .i2cspeed = I2C_SPEED_800K, +}; + +struct _FuDellDockMst { + FuDevice parent_instance; + FuDevice *symbiote; + guint8 unlock_target; + guint relock_id; + guint64 blob_major_offset; + guint64 blob_minor_offset; + guint64 blob_build_offset; +}; + +G_DEFINE_TYPE (FuDellDockMst, fu_dell_dock_mst, FU_TYPE_DEVICE) + +/** + * fu_dell_dock_mst_get_bank_attribs: + * @bank: An MSTBank + * @out (out): The MSTBankAttributes attribute that matches + * @error: the #GError, or %NULL + * + * Returns a structure that corresponds to the attributes for a bank + * + * Returns: %TRUE for success + **/ +static gboolean +fu_dell_dock_mst_get_bank_attribs (MSTBank bank, + const MSTBankAttributes **out, + GError **error) +{ + switch (bank) { + case Bank0: + *out = &bank0_attributes; + break; + case Bank1: + *out = &bank1_attributes; + break; + case ESM: + *out = &esm_attributes; + break; + default: + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Invalid bank specified %u", bank); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_dell_dock_mst_rc_command (FuDevice *symbiote, + guint8 cmd, + guint32 length, + guint32 offset, + const guint8 *data, + GError **error); + +static gboolean +fu_dell_dock_mst_read_register (FuDevice *symbiote, + guint32 address, + gsize length, + GBytes **bytes, + GError **error) +{ + g_autoptr(GError) error_local = NULL; + + g_return_val_if_fail (symbiote != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (length <= 32, FALSE); + + /* write the offset we're querying */ + if (!fu_dell_dock_hid_i2c_write (symbiote, (guint8 *) &address, 4, + &mst_base_settings, &error_local)) + return FALSE; + + /* read data for the result */ + if (!fu_dell_dock_hid_i2c_read (symbiote, 0, length, bytes, + &mst_base_settings, &error_local)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_write_register (FuDevice *symbiote, + guint32 address, + guint8 *data, + gsize length, + GError **error) +{ + g_autoptr(GError) error_local = NULL; + guint8 buffer[length + 4]; + memcpy (buffer, &address, 4); + memcpy (buffer + 4, data, length); + + g_return_val_if_fail (symbiote != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + /* write the offset we're querying */ + return fu_dell_dock_hid_i2c_write (symbiote, buffer, length + 4, + &mst_base_settings, &error_local); +} + +static gboolean +fu_dell_dock_mst_query_active_bank (FuDevice *symbiote, + MSTBank *active, + GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + const guint32 *data = NULL; + gsize length = 4; + + if (!fu_dell_dock_mst_read_register (symbiote, MST_CORE_MCU_BOOTLOADER_STS, + length, &bytes, error)) { + g_prefix_error (error, "Failed to query active bank: "); + return FALSE; + } + + data = g_bytes_get_data (bytes, &length); + if ((data[0] & (1 << 7)) || (data[0] & (1 << 30))) + *active = Bank1; + else + *active = Bank0; + g_debug ("MST: active bank is: %u", *active); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_disable_remote_control (FuDevice *symbiote, GError **error) +{ + g_debug ("MST: Disabling remote control"); + return fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_DISABLE_REMOTE_CONTROL, + 0, 0, + NULL, + error); +} + +static gboolean +fu_dell_dock_mst_enable_remote_control (FuDevice *symbiote, GError **error) +{ + g_autoptr(GError) error_local = NULL; + const gchar *data = "PRIUS"; + + g_debug ("MST: Enabling remote control"); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_ENABLE_REMOTE_CONTROL, + 5, 0, + (guint8 *) data, + &error_local)) { + g_debug ("Failed to enable remote control: %s", + error_local->message); + /* try to disable / re-enable */ + if (!fu_dell_dock_mst_disable_remote_control (symbiote, error)) + return FALSE; + return fu_dell_dock_mst_enable_remote_control (symbiote, error); + } + return TRUE; +} + +static gboolean +fu_dell_dock_trigger_rc_command (FuDevice *symbiote, GError **error) +{ + const guint8 *result = NULL; + guint32 tmp; + + /* Trigger the write */ + tmp = MST_TRIGGER_WRITE; + if (!fu_dell_dock_mst_write_register (symbiote, + MST_RC_TRIGGER_ADDR, + (guint8 *) &tmp, sizeof(guint32), + error)) { + g_prefix_error (error, "Failed to write MST_RC_TRIGGER_ADDR: "); + return FALSE; + } + /* poll for completion */ + tmp = 0xffff; + for (guint i = 0; i < 1000; i++) { + g_autoptr(GBytes) bytes = NULL; + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_COMMAND_ADDR, + sizeof(guint32), &bytes, + error)) { + g_prefix_error (error, + "Failed to poll MST_RC_COMMAND_ADDR"); + return FALSE; + } + result = g_bytes_get_data (bytes, NULL); + /* complete */ + if ((result[2] & 0x80) == 0) { + tmp = result[3]; + break; + } + g_usleep (2000); + } + switch (tmp) { + /* need to enable remote control */ + case 4: + return fu_dell_dock_mst_enable_remote_control (symbiote, error); + /* error scenarios */ + case 3: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown error"); + return FALSE; + case 2: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unsupported command"); + return FALSE; + case 1: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid argument"); + return FALSE; + /* success scenario */ + case 0: + return TRUE; + + default: + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Command timed out or unknown failure: %x", + tmp); + return FALSE; + } +} + +static gboolean +fu_dell_dock_mst_rc_command (FuDevice *symbiote, + guint8 cmd, + guint32 length, + guint32 offset, + const guint8 *data, + GError **error) +{ + /* 4 for cmd, 4 for offset, 4 for length, 4 for garbage */ + gint buffer_len = (data == NULL) ? 12 : length + 16; + guint8 buffer[buffer_len]; + guint32 tmp; + + g_return_val_if_fail (symbiote != NULL, FALSE); + + /* command */ + tmp = (cmd | 0x80) << 16; + memcpy (buffer, &tmp, 4); + /* offset */ + memcpy (buffer + 4, &offset, 4); + /* length */ + memcpy (buffer + 8, &length, 4); + /* data */ + if (data != NULL) + memcpy (buffer + 16, data, length); + + /* write the combined register stream */ + if (!fu_dell_dock_mst_write_register (symbiote, MST_RC_COMMAND_ADDR, + buffer, buffer_len, error)) + return FALSE; + + return fu_dell_dock_trigger_rc_command (symbiote, error); +} + +static gboolean +fu_dell_dock_mst_read_chipid (FuDevice *symbiote, + guint16 *chip_id, + GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + const guint8 *data; + gsize length = 4; + + g_return_val_if_fail (chip_id != NULL, FALSE); + + /* run an RC command to get data from memory */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_MEMORY, + length, MST_CHIPID_OFFSET, + NULL, + error)) + return FALSE; + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + length, + &bytes, + error)) + return FALSE; + data = g_bytes_get_data (bytes, &length); + *chip_id = (data[1] << 8) | data[2]; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_check_offset (guint8 byte, guint8 offset) +{ + if ((byte & offset) > 0) + return TRUE; + return FALSE; +} + +static gboolean +fu_d19_mst_check_fw (FuDevice *symbiote, GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + const guint8 *data; + gsize length = 4; + + if (!fu_dell_dock_mst_read_register (symbiote, + MST_CORE_MCU_BOOTLOADER_STS, + length, &bytes, + error)) + return FALSE; + data = g_bytes_get_data (bytes, &length); + + g_debug ("MST: firmware check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x01)); + g_debug ("MST: HDCP key check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x02)); + g_debug ("MST: Config0 check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x04)); + g_debug ("MST: Config1 check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x08)); + + if (fu_dell_dock_mst_check_offset (data[0], 0xF0)) + g_debug ("MST: running in bootloader"); + else + g_debug ("MST: running in firmware"); + g_debug ("MST: Error code: %x", data[1]); + g_debug ("MST: GPIO boot strap record: %d", data[2]); + g_debug ("MST: Bootloader version number %x", data[3]); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_get_version_direct (FuDevice *symbiote, gchar **version_out, + GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + const guint8 *data; + gsize length = 4; + + g_return_val_if_fail (version_out != NULL, FALSE); + + /* Try to read core MCU FW version */ + if (!fu_dell_dock_mst_read_register (symbiote, + MST_CORE_MCU_FW_VERSION, + length, &bytes, + error)) + return FALSE; + data = g_bytes_get_data (bytes, &length); + if (length < 4) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid MST result %" G_GSIZE_FORMAT, length); + return FALSE; + } + *version_out = g_strdup_printf ("%02x.%02x.%02x", + data[1], /* major */ + data[0], /* minor */ + data[2]); /* build */ + return TRUE; +} + +static gboolean +fu_dell_dock_mst_checksum_bank (FuDevice *symbiote, + GBytes *blob_fw, + MSTBank bank, + gboolean *checksum, + GError **error) +{ + g_autoptr(GBytes) csum_bytes = NULL; + const MSTBankAttributes *attribs = NULL; + gsize length = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &length); + guint32 payload_sum = 0; + guint32 bank_sum = 0; + + g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (checksum != NULL, FALSE); + + if (!fu_dell_dock_mst_get_bank_attribs (bank, &attribs, error)) + return FALSE; + + /* bank is specified outside of payload */ + if (attribs->start + attribs->length > length) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Payload %u is bigger than bank %u", + attribs->start + attribs->length, bank); + return FALSE; + } + + /* checksum the file */ + for (guint i = attribs->start; i < attribs->length + attribs->start; + i++) { + payload_sum += data[i]; + } + g_debug ("MST: Payload checksum: 0x%x", payload_sum); + + /* checksum the bank */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_CHECKSUM, + attribs->length, attribs->start, + NULL, + error)) { + g_prefix_error (error, "Failed to checksum bank %u: ", bank); + return FALSE; + } + /* read result from data register */ + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + 4, &csum_bytes, error)) + return FALSE; + data = g_bytes_get_data (csum_bytes, NULL); + bank_sum = GUINT32_FROM_LE (data[0] | data[1] << 8 | data[2] << 16 | + data[3] << 24); + g_debug ("MST: Bank %u checksum: 0x%x", bank, bank_sum); + + *checksum = (bank_sum == payload_sum); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_erase_bank (FuDevice *symbiote, MSTBank bank, GError **error) +{ + const MSTBankAttributes *attribs = NULL; + guint32 sector; + + if (!fu_dell_dock_mst_get_bank_attribs (bank, &attribs, error)) + return FALSE; + + for (guint32 i = attribs->start; i < attribs->start + attribs->length; + i += 0x10000) { + sector = FLASH_SECTOR_ERASE_64K | (i / 0x10000); + g_debug ("MST: Erasing sector 0x%x", sector); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_ERASE_FLASH, + 4, 0, + (guint8 *) §or, + error)) { + g_prefix_error ( + error, "Failed to erase sector 0x%x: ", sector); + return FALSE; + } + } + g_debug ("MST: Waiting for flash clear to settle"); + g_usleep (5000000); + + return TRUE; +} + +static gboolean +fu_dell_dock_write_flash_bank (FuDevice *device, + GBytes *blob_fw, + MSTBank bank, + GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + const MSTBankAttributes *attribs = NULL; + gsize write_size = 32; + guint end; + const guint8 *data = g_bytes_get_data (blob_fw, NULL); + + g_return_val_if_fail (blob_fw != NULL, FALSE); + + if (!fu_dell_dock_mst_get_bank_attribs (bank, &attribs, error)) + return FALSE; + end = attribs->start + attribs->length; + + g_debug ("MST: Writing payload to bank %u", bank); + for (guint i = attribs->start; i < end; i += write_size) { + if (!fu_dell_dock_mst_rc_command (self->symbiote, + MST_CMD_WRITE_FLASH, + write_size, i, + data + i, + error)) { + g_prefix_error ( + error, + "Failed to write bank %u payload offset 0x%x: ", + bank, i); + return FALSE; + } + fu_device_set_progress_full (device, + i - attribs->start, + end - attribs->start); + } + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_stop_esm (FuDevice *symbiote, GError **error) +{ + g_autoptr(GBytes) quad_bytes = NULL; + g_autoptr(GBytes) hdcp_bytes = NULL; + guint32 payload = 0x21; + gsize length = sizeof(guint32); + const guint8 *data; + guint8 data_out[length]; + + /* disable ESM first */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_MEMORY, + length, MST_RC_TRIGGER_ADDR, + (guint8 *) &payload, + error)) + return FALSE; + + /* waiting for ESM exit */ + g_usleep(200); + + /* disable QUAD mode */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_MEMORY, + length, MST_REG_QUAD_DISABLE, + NULL, + error)) + return FALSE; + + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + length, &quad_bytes, + error)) + return FALSE; + + data = g_bytes_get_data (quad_bytes, &length); + memcpy (data_out, data, length); + data_out[0] = 0x00; + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_MEMORY, + length, MST_REG_QUAD_DISABLE, + data_out, error)) + return FALSE; + + /* disable HDCP2.2 */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_MEMORY, + length, MST_REG_HDCP22_DISABLE, + NULL, + error)) + return FALSE; + + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + length, + &hdcp_bytes, + error)) + return FALSE; + + data = g_bytes_get_data (hdcp_bytes, &length); + memcpy (data_out, data, length); + data_out[0] = data[0] & (1 << 2); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_MEMORY, + length, MST_REG_HDCP22_DISABLE, + data, + error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_invalidate_bank (FuDevice *symbiote, MSTBank bank_in_use, + GError **error) +{ + const MSTBankAttributes *attribs; + g_autoptr(GBytes) bytes = NULL; + const guint8 *crc_tag; + const guint8 *new_tag; + guint32 crc_offset; + guint retries = 2; + + if (!fu_dell_dock_mst_get_bank_attribs (bank_in_use, &attribs, error)) { + g_prefix_error (error, "unable to invalidate bank: "); + return FALSE; + } + /* we need to write 4 byte increments over I2C so this differs from DP aux */ + crc_offset = attribs->start + EEPROM_TAG_OFFSET + 12; + + /* Read CRC byte to flip */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_FLASH, + 4, crc_offset, + NULL, + error)) { + + g_prefix_error (error, "failed to read tag from flash: "); + return FALSE; + } + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + 1, + &bytes, + error)) { + return FALSE; + } + crc_tag = g_bytes_get_data (bytes, NULL); + g_debug ("CRC byte is currently 0x%x", crc_tag[3]); + + for (guint32 retries_cnt = 0; ; retries_cnt++) { + g_autoptr(GBytes) bytes_new = NULL; + /* CRC8 is not 0xff, erase last 4k of bank# */ + if (crc_tag[3] != 0xff) { + guint32 sector = FLASH_SECTOR_ERASE_4K + + (attribs->start + attribs->length - 0x1000) / 0x1000; + g_debug ("Erasing 4k from sector 0x%x invalidate bank %u", + sector, bank_in_use); + /* offset for last 4k of bank# */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_ERASE_FLASH, + 4, 0, + (guint8 *) §or, + error)) { + + g_prefix_error (error, + "failed to erase sector 0x%x: ", + sector); + return FALSE; + } + /* CRC8 is 0xff, set it to 0x00 */ + } else { + guint32 write = 0x00; + g_debug ("Writing 0x00 byte to 0x%x to invalidate bank %u", + crc_offset, bank_in_use); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_FLASH, + 4, crc_offset, + (guint8*) &write, + error)) { + + g_prefix_error (error, "failed to clear CRC byte: "); + return FALSE; + } + } + /* re-read for comparison */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_FLASH, + 4, crc_offset, + NULL, + error)) { + + g_prefix_error (error, "failed to read tag from flash: "); + return FALSE; + } + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + 4, &bytes_new, + error)) { + return FALSE; + } + new_tag = g_bytes_get_data (bytes_new, NULL); + g_debug ("CRC byte is currently 0x%x", new_tag[3]); + + /* tag succesfully cleared */ + if ((new_tag[3] == 0xff && crc_tag[3] != 0xff) || + (new_tag[3] == 0x00 && crc_tag[3] == 0xff)) { + break; + } + if (retries_cnt > retries) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "set tag invalid fail (new 0x%x; old 0x%x)", + new_tag[3], crc_tag[3]); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_write_fw (FuDevice *device, + GBytes *blob_fw, + GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + MSTBank bank_in_use = 0; + guint retries = 2; + gboolean checksum = FALSE; + guint8 order[3] = {Bank0, ESM}; + guint16 chip_id; + const guint8* data = g_bytes_get_data (blob_fw, NULL); + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (self->symbiote != NULL, FALSE); + + /* in case update was scheduled immediately after setup */ + if (self->relock_id > 0) { + g_source_remove (self->relock_id); + self->relock_id = 0; + } + + dynamic_version = g_strdup_printf ("%02x.%02x.%02x", + data[self->blob_major_offset], + data[self->blob_minor_offset], + data[self->blob_build_offset]); + g_debug ("Writing firmware version %s", dynamic_version); + + /* determine the flash order */ + if (!fu_dell_dock_mst_query_active_bank (self->symbiote, &bank_in_use, error)) + return FALSE; + + if (bank_in_use == Bank0) + order[0] = Bank1; + + /* enable remote control */ + if (!fu_dell_dock_mst_enable_remote_control (self->symbiote, error)) + return FALSE; + + /* Read Synaptics MST chip ID */ + if (!fu_dell_dock_mst_read_chipid (self->symbiote, &chip_id, + error)) + return FALSE; + if (chip_id != EXPECTED_CHIPID) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown MST chip found %x", chip_id); + return FALSE; + } + + /* ESM needs special handling during flash process*/ + if (!fu_dell_dock_mst_stop_esm (self->symbiote, error)) + return FALSE; + + /* Write each bank in order */ + for (guint phase = 0; phase < 2; phase++) { + g_debug ("MST: Checking bank %u", order[phase]); + if (!fu_dell_dock_mst_checksum_bank (self->symbiote, + blob_fw, + order[phase], + &checksum, error)) + return FALSE; + if (checksum) { + g_debug ("MST: bank %u is already up to date", order[phase]); + continue; + } + g_debug ("MST: bank %u needs to be updated", order[phase]); + for (guint i = 0; i < retries; i++) { + fu_device_set_progress_full (device, 0, 100); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_dell_dock_mst_erase_bank (self->symbiote, + order[phase], + error)) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_dell_dock_write_flash_bank (device, blob_fw, + order[phase], error)) + return FALSE; + if (!fu_dell_dock_mst_checksum_bank (self->symbiote, + blob_fw, + order[phase], + &checksum, + error)) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!checksum) { + g_debug ( + "MST: Failed to verify checksum on bank %u", + order[phase]); + continue; + } + g_debug ("MST: Bank %u successfully flashed", order[phase]); + break; + } + /* failed after all our retries */ + if (!checksum) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to write to bank %u", order[phase]); + return FALSE; + } + } + /* invalidate the previous bank */ + if (!fu_dell_dock_mst_invalidate_bank (self->symbiote, bank_in_use, error)) { + g_prefix_error (error, "failed to invalidate bank %u: ", bank_in_use); + return FALSE; + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + + /* disable remote control now */ + return fu_dell_dock_mst_disable_remote_control (self->symbiote, error); +} + +static gboolean +fu_dell_dock_mst_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockBlobMajorOffset") == 0) { + self->blob_major_offset = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobMinorOffset") == 0) { + self->blob_minor_offset = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobBuildOffset") == 0) { + self->blob_build_offset = fu_common_strtoull (value); + return TRUE; + } + else if (g_strcmp0 (key, "DellDockInstallDurationI2C") == 0) { + guint64 tmp = fu_common_strtoull (value); + fu_device_set_install_duration (device, tmp); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static gboolean +fu_dell_dock_mst_relock (gpointer user_data) +{ + FuDellDockMst *self = (FuDellDockMst *) user_data; + FuDevice *device = FU_DEVICE (self); + g_autoptr(GError) error_local = NULL; + gboolean ret; + + self->relock_id = 0; + g_debug ("MST relock called"); + /* only call if parent still around */ + if (fu_device_get_parent (device) != NULL) { + ret = fu_dell_dock_set_power (device, self->unlock_target, + FALSE, &error_local); + if (!ret) + g_warning ("%s", error_local->message); + } + return G_SOURCE_REMOVE; +} + +static gboolean +fu_dell_dock_mst_setup (FuDevice *device, GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + FuDevice *parent; + const gchar *version; + g_autofree gchar *dynamic_version = NULL; + + /* Open up access to the controller + * - This is left open with a timeout to allow DP aux to initialize + * - This intentionally isn't called in open, it should be called by + * plugin during update + */ + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + self->relock_id = g_timeout_add (6000, fu_dell_dock_mst_relock, self); + + /* sanity check that we can talk to MST */ + if (!fu_d19_mst_check_fw (self->symbiote, error)) + return FALSE; + + /* set version from EC if we know it */ + parent = fu_device_get_parent (device); + version = fu_dell_dock_ec_get_mst_version (parent); + + /* TODO: Potentially remove direct probe if we know EC return correct + * value at all times + */ + if (version == NULL) { + if (!fu_dell_dock_mst_get_version_direct (self->symbiote, + &dynamic_version, + error)) + return FALSE; + version = dynamic_version; + } + if (version != NULL) + fu_device_set_version (device, version); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_probe (FuDevice *device, GError **error) +{ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_logical_id (FU_DEVICE (device), "mst"); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_open (FuDevice *device, GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + FuDevice *parent = fu_device_get_parent (device); + + g_return_val_if_fail (self->unlock_target != 0, FALSE); + g_return_val_if_fail (parent != NULL, FALSE); + + if (self->symbiote == NULL) + self->symbiote = g_object_ref (fu_dell_dock_ec_get_symbiote (parent)); + + if (!fu_device_open (self->symbiote, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_close (FuDevice *device, GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + + return fu_device_close (self->symbiote, error); +} + +static void +fu_dell_dock_mst_finalize (GObject *object) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (object); + if (self->relock_id > 0) { + g_source_remove (self->relock_id); + self->relock_id = 0; + fu_dell_dock_mst_relock (self); + } + g_object_unref (self->symbiote); + G_OBJECT_CLASS (fu_dell_dock_mst_parent_class)->finalize (object); +} + +static void +fu_dell_dock_mst_init (FuDellDockMst *self) +{ +} + +static void +fu_dell_dock_mst_class_init (FuDellDockMstClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_mst_finalize; + klass_device->probe = fu_dell_dock_mst_probe; + klass_device->open = fu_dell_dock_mst_open; + klass_device->close = fu_dell_dock_mst_close; + klass_device->setup = fu_dell_dock_mst_setup; + klass_device->probe = fu_dell_dock_mst_probe; + klass_device->write_firmware = fu_dell_dock_mst_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_mst_set_quirk_kv; +} + +FuDellDockMst * +fu_dell_dock_mst_new (void) +{ + FuDellDockMst *device = NULL; + device = g_object_new (FU_TYPE_DELL_DOCK_MST, NULL); + return device; +} diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.h b/plugins/dell-dock/fu-dell-dock-i2c-mst.h new file mode 100644 index 000000000..18ada5b52 --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#ifndef __FU_DELL_DOCK_I2C_MST_H +#define __FU_DELL_DOCK_I2C_MST_H + +#include "config.h" + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_MST (fu_dell_dock_mst_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockMst, fu_dell_dock_mst, FU, DELL_DOCK_MST, FuDevice) + +FuDellDockMst *fu_dell_dock_mst_new (void); + +G_END_DECLS + +#endif /* __FU_DELL_DOCK_I2C_MST_H */ diff --git a/plugins/dell-dock/fu-dell-dock-status.c b/plugins/dell-dock/fu-dell-dock-status.c new file mode 100644 index 000000000..8061c0419 --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-status.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include +#include + +#include "fu-dell-dock-common.h" + +struct _FuDellDockStatus { + FuDevice parent_instance; + guint64 blob_version_offset; +}; + +G_DEFINE_TYPE (FuDellDockStatus, fu_dell_dock_status, FU_TYPE_DEVICE) + +static gchar * +fu_dell_dock_status_ver_string (guint32 status_version) +{ + /* guint32 BCD */ + return g_strdup_printf ("%02x.%02x.%02x.%02x", + status_version & 0xff, + (status_version >> 8) & 0xff, + (status_version >> 16) & 0xff, + (status_version >> 24) & 0xff); +} + +static gboolean +fu_dell_dock_status_setup (FuDevice *device, GError **error) +{ + FuDevice *parent; + guint32 status_version; + g_autofree gchar *dynamic_version = NULL; + + parent = fu_device_get_parent (device); + status_version = fu_dell_dock_ec_get_status_version (parent); + + dynamic_version = fu_dell_dock_status_ver_string (status_version); + fu_device_set_version (device, dynamic_version); + fu_device_set_logical_id (FU_DEVICE (device), "status"); + + return TRUE; +} + +static gboolean +fu_dell_dock_status_write (FuDevice *device, + GBytes *blob_fw, + GError **error) +{ + FuDellDockStatus *self = FU_DELL_DOCK_STATUS (device); + FuDevice *parent; + gsize length = 0; + guint32 status_version = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &length); + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + memcpy (&status_version, data + self->blob_version_offset, sizeof (guint32)); + dynamic_version = fu_dell_dock_status_ver_string (status_version); + g_debug ("Writing firmware version %s", dynamic_version); + + parent = fu_device_get_parent (device); + if (!fu_dell_dock_ec_commit_package (parent, blob_fw, error)) + return FALSE; + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + + return TRUE; +} + +static gboolean +fu_dell_dock_status_open (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + + g_return_val_if_fail (parent != NULL, FALSE); + + return fu_device_open (parent, error); +} + +static gboolean +fu_dell_dock_status_close (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + + return fu_device_close (parent, error); +} + +static gboolean +fu_dell_dock_status_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockStatus *self = FU_DELL_DOCK_STATUS (device); + if (g_strcmp0 (key, "DellDockBlobVersionOffset") == 0) { + self->blob_version_offset = fu_common_strtoull (value); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_dell_dock_status_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_dell_dock_status_parent_class)->finalize (object); +} + +static void +fu_dell_dock_status_init (FuDellDockStatus *self) +{ +} + +static void +fu_dell_dock_status_class_init (FuDellDockStatusClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_status_finalize; + klass_device->write_firmware = fu_dell_dock_status_write; + klass_device->setup = fu_dell_dock_status_setup; + klass_device->open = fu_dell_dock_status_open; + klass_device->close = fu_dell_dock_status_close; + klass_device->set_quirk_kv = fu_dell_dock_status_set_quirk_kv; +} + +FuDellDockStatus * +fu_dell_dock_status_new (void) +{ + FuDellDockStatus *self = NULL; + self = g_object_new (FU_TYPE_DELL_DOCK_STATUS, NULL); + return self; +} diff --git a/plugins/dell-dock/fu-dell-dock-status.h b/plugins/dell-dock/fu-dell-dock-status.h new file mode 100644 index 000000000..f987a325d --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-status.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#ifndef __FU_DELL_DOCK_STATUS_H +#define __FU_DELL_DOCK_STATUS_H + +#include "config.h" + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_STATUS (fu_dell_dock_status_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockStatus, fu_dell_dock_status, FU, DELL_DOCK_STATUS, FuDevice) + +FuDellDockStatus *fu_dell_dock_status_new (void); + +G_END_DECLS + +#endif /* __FU_DELL_DOCK_STATUS_H */ diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c new file mode 100644 index 000000000..b1b5e7f64 --- /dev/null +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include "fu-device.h" +#include "fwupd-error.h" +#include "fu-plugin-vfuncs.h" + +#include "fu-dell-dock-common.h" + +struct FuPluginData { + gboolean synaptics_functional; +}; + +void fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof(FuPluginData)); + + /* allow these to be built by quirks */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + g_type_ensure (FU_TYPE_DELL_DOCK_STATUS); + g_type_ensure (FU_TYPE_DELL_DOCK_MST); +} + +static gboolean +fu_plugin_dell_dock_get_synaptics_unlock (FuPlugin *plugin, guint8 *target, + GError **error) +{ + const gchar *target_str = fu_plugin_lookup_quirk_by_id (plugin, + "DellDockUnlockTargets", + "synapticsmst"); + guint64 tmp; + + g_return_val_if_fail (target != NULL, FALSE); + + tmp = fu_common_strtoull (target_str); + if (tmp < G_MAXUINT8) { + *target = tmp; + return TRUE; + } + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "Unsupported unlock target %s", + target_str); + return FALSE; +} + +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + if (g_strcmp0 (fu_device_get_plugin (device), "synapticsmst") != 0) + return; + + /* not a perfect heuristic; but good enough - disable extra coldplug */ + if (fu_device_has_custom_flag (device, "skip-restart")) { + FuPluginData *data = fu_plugin_get_data (plugin); + g_debug ("%s registered via Synaptics MST plugin, disabling extra coldplug", + fu_device_get_name (device)); + data->synaptics_functional = TRUE; + } +} + +static gboolean +fu_plugin_dell_dock_create_node (FuPlugin *plugin, + FuDevice *device, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + fu_device_set_quirks (device, fu_plugin_get_quirks (plugin)); + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + fu_plugin_device_add (plugin, device); + + return TRUE; +} + +static gboolean +fu_plugin_dell_dock_probe (FuPlugin *plugin, + FuDevice *symbiote, + GError **error) +{ + g_autoptr(FuDellDockEc) ec_device = NULL; + + /* create all static endpoints */ + ec_device = fu_dell_dock_ec_new (symbiote); + if (!fu_plugin_dell_dock_create_node (plugin, + FU_DEVICE (ec_device), + error)) + return FALSE; + + return TRUE; +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, + FuUsbDevice *device, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDellDockHub) hub = fu_dell_dock_hub_new (device); + FuDevice *fu_device = FU_DEVICE (hub); + const gchar *key = NULL; + + locker = fu_device_locker_new (fu_device, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, fu_device); + + if (fu_device_has_custom_flag (fu_device, "has-bridge")) { + g_autoptr(GError) error_local = NULL; + + /* only add the device with parent to cache */ + key = fu_device_get_id (fu_device); + if (fu_plugin_cache_lookup (plugin, key) != NULL) { + g_debug ("Ignoring already added device %s", key); + return TRUE; + } + fu_plugin_cache_add (plugin, key, fu_device); + + /* probe for extended devices */ + if (!fu_plugin_dell_dock_probe (plugin, + fu_device, + &error_local)) { + g_warning ("Failed to probe bridged devices for %s: %s", + key, + error_local->message); + } + + /* reprobe for synaptics when adding bridge */ + g_debug ("Synaptics MST over DP aux functional: %d", data->synaptics_functional); +#if defined(HAVE_SYNAPTICS) + if (!data->synaptics_functional) { + fu_plugin_set_coldplug_delay (plugin, 2000); + fu_plugin_request_recoldplug (plugin); + } +#endif + } + + return TRUE; +} + +gboolean +fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + const gchar *device_key = fu_device_get_id (device); + FuDevice *dev; + FuDevice *parent; + + /* only the device with bridge will be in cache */ + dev = fu_plugin_cache_lookup (plugin, device_key); + if (dev == NULL) + return TRUE; + fu_plugin_cache_remove (plugin, device_key); + + /* find the parent and ask daemon to remove whole chain */ + parent = fu_device_get_parent (dev); + if (parent != NULL && FU_IS_DELL_DOCK_EC (parent)) { + g_debug ("Removing %s (%s)", + fu_device_get_name (parent), + fu_device_get_id (parent)); + fu_plugin_device_remove (plugin, parent); + /* we don't know this anymore */ + data->synaptics_functional = FALSE; + } + + return TRUE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *dev, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + + fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_device_write_firmware (dev, blob_fw, error)) { + g_prefix_error (error, + "failed to update %s: ", + fu_device_get_name (dev)); + return FALSE; + } + fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART); + + return TRUE; +} + +/* prefer to use EC if in the transaction and parent if it is not */ +static FuDevice * +fu_plugin_dell_dock_get_ec (GPtrArray *devices) +{ + FuDevice *ec_parent = NULL; + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + FuDevice *parent; + if (FU_IS_DELL_DOCK_EC (dev)) + return dev; + parent = fu_device_get_parent (dev); + if (parent != NULL && FU_IS_DELL_DOCK_EC (parent)) + ec_parent = parent; + } + + return ec_parent; +} + +gboolean +fu_plugin_composite_prepare (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + FuDevice *parent = fu_plugin_dell_dock_get_ec (devices); + gboolean remaining_replug = FALSE; + + if (parent == NULL) + return TRUE; + + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + /* if synaptics is part of the transaction via DP aux turn it on */ + if (g_strcmp0 (fu_device_get_plugin (dev), "synapticsmst") == 0) { + guint8 target; + if (fu_device_get_parent (dev) != parent) + continue; + if (!fu_plugin_dell_dock_get_synaptics_unlock (plugin, &target, error)) + return FALSE; + if (!fu_dell_dock_set_power (parent, target, TRUE, error)) + return FALSE; + /* if thunderbolt is part of transaction our family is leaving us */ + } else if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0) { + if (fu_device_get_parent (dev) != parent) + continue; + fu_dell_dock_will_replug (parent); + /* set all other devices to replug */ + remaining_replug = TRUE; + continue; + } + /* different device */ + if (fu_device_get_parent (dev) != parent) + continue; + if (remaining_replug) + fu_dell_dock_will_replug (dev); + } + + return TRUE; +} + +gboolean +fu_plugin_composite_cleanup (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + FuDevice *parent = fu_plugin_dell_dock_get_ec (devices); + g_autoptr(FuDeviceLocker) locker = NULL; + + if (parent == NULL) + return TRUE; + + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + + return fu_dell_dock_ec_reboot_dock (parent, error); +} diff --git a/plugins/dell-dock/meson.build b/plugins/dell-dock/meson.build new file mode 100644 index 000000000..214420b50 --- /dev/null +++ b/plugins/dell-dock/meson.build @@ -0,0 +1,29 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginDellDock"'] + +install_data(['dell-dock.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_dell_dock', + sources : [ + 'fu-plugin-dell-dock.c', + 'fu-dell-dock-common.c', + 'fu-dell-dock-hid.c', + 'fu-dell-dock-status.c', + 'fu-dell-dock-i2c-ec.c', + 'fu-dell-dock-hub.c', + 'fu-dell-dock-i2c-mst.c' + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + gudev, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index f9113814f..e62f82c5e 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -3,6 +3,7 @@ subdir('colorhug') subdir('ebitdo') subdir('flashrom') subdir('steelseries') +subdir('dell-dock') subdir('nitrokey') subdir('rts54hid') subdir('rts54hub') diff --git a/plugins/synapticsmst/fu-plugin-synapticsmst.c b/plugins/synapticsmst/fu-plugin-synapticsmst.c index 83c9eee93..52149edd1 100644 --- a/plugins/synapticsmst/fu-plugin-synapticsmst.c +++ b/plugins/synapticsmst/fu-plugin-synapticsmst.c @@ -463,4 +463,7 @@ fu_plugin_init (FuPlugin *plugin) { /* make sure dell is already coldplugged */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "dell"); + + /* dell-dock plugin uses a slower bus for flashing */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } diff --git a/plugins/synapticsmst/synapticsmst.quirk b/plugins/synapticsmst/synapticsmst.quirk index d3f8fa488..75a25f46b 100644 --- a/plugins/synapticsmst/synapticsmst.quirk +++ b/plugins/synapticsmst/synapticsmst.quirk @@ -38,3 +38,7 @@ DeviceKind = wld15 [SynapticsMSTBoardID=277] Name = Dell Rugged Platform DeviceKind = system + +[SynapticsMSTBoardID=259] +Name = Dell dock +DeviceKind = panamera From c8faf5e69ff026094df314d796ccacfeba24e1e6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 8 Sep 2018 09:34:37 +0100 Subject: [PATCH 011/254] trivial: Do not allow VLA features in plugins --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 58a0d1653..20dbdba8f 100644 --- a/meson.build +++ b/meson.build @@ -100,6 +100,7 @@ warning_flags = [ '-Wuninitialized', '-Wunused-but-set-variable', '-Wunused-variable', + '-Wvla', '-Wwrite-strings' ] cc = meson.get_compiler('c') From 5e84da6bfe641508f23f585b477d6c3753b2865a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 12 Oct 2018 08:08:14 +0100 Subject: [PATCH 012/254] dell-dock: Don't use the VLA feature in the new dock This is a massive co-incidence. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 2 +- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 4f4a5c833..db4e15060 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -594,7 +594,7 @@ fu_dell_dock_ec_commit_package (FuDevice *device, GBytes *blob_fw, FuDellDockEc *self = FU_DELL_DOCK_EC (device); gsize length = 0; const guint8 *data = g_bytes_get_data (blob_fw, &length); - guint8 payload[length + 2]; + g_autofree guint8 *payload = g_malloc0 (length + 2); g_return_val_if_fail (device != NULL, FALSE); g_return_val_if_fail (blob_fw != NULL, FALSE); diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index e92cc603a..a1417466c 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -189,7 +189,7 @@ fu_dell_dock_mst_write_register (FuDevice *symbiote, GError **error) { g_autoptr(GError) error_local = NULL; - guint8 buffer[length + 4]; + g_autofree guint8 *buffer = g_malloc0 (length + 4); memcpy (buffer, &address, 4); memcpy (buffer + 4, data, length); @@ -333,7 +333,7 @@ fu_dell_dock_mst_rc_command (FuDevice *symbiote, { /* 4 for cmd, 4 for offset, 4 for length, 4 for garbage */ gint buffer_len = (data == NULL) ? 12 : length + 16; - guint8 buffer[buffer_len]; + g_autofree guint8 *buffer = g_malloc0 (buffer_len); guint32 tmp; g_return_val_if_fail (symbiote != NULL, FALSE); @@ -593,7 +593,7 @@ fu_dell_dock_mst_stop_esm (FuDevice *symbiote, GError **error) guint32 payload = 0x21; gsize length = sizeof(guint32); const guint8 *data; - guint8 data_out[length]; + guint8 data_out[sizeof(guint32)]; /* disable ESM first */ if (!fu_dell_dock_mst_rc_command (symbiote, From 6abc2b9e0edb5d4d0034d89bd1ac2908d88be0a0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 12 Oct 2018 09:36:12 +0100 Subject: [PATCH 013/254] trivial: Remove some pretty intense debugging that crept in --- plugins/unifying/fu-unifying-hidpp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/unifying/fu-unifying-hidpp.c b/plugins/unifying/fu-unifying-hidpp.c index b60e67ba4..d397d37cb 100644 --- a/plugins/unifying/fu-unifying-hidpp.c +++ b/plugins/unifying/fu-unifying-hidpp.c @@ -200,7 +200,7 @@ fu_unifying_hidpp_transfer (gint fd, FuUnifyingHidppMsg *msg, GError **error) return FALSE; } - g_error ("ignoring message %u", ignore_cnt); + g_debug ("ignoring message %u", ignore_cnt); }; /* copy over data */ From c012c815405cc3499291d93eab4820d09101ba6a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 12 Oct 2018 10:08:13 +0100 Subject: [PATCH 014/254] dell-dock: Use different debug strings for each device type --- plugins/dell-dock/fu-dell-dock-hub.c | 2 +- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 2 +- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 2 +- plugins/dell-dock/fu-dell-dock-status.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-hub.c b/plugins/dell-dock/fu-dell-dock-hub.c index 4966de37b..f0f6d0dd1 100644 --- a/plugins/dell-dock/fu-dell-dock-hub.c +++ b/plugins/dell-dock/fu-dell-dock-hub.c @@ -67,7 +67,7 @@ fu_dell_dock_hub_write_fw (FuDevice *device, dynamic_version = g_strdup_printf ("%02x.%02x", data[self->blob_major_offset], data[self->blob_minor_offset]); - g_debug ("Writing firmware version %s", dynamic_version); + g_debug ("writing hub firmware version %s", dynamic_version); if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) return FALSE; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index db4e15060..18b431207 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -653,7 +653,7 @@ fu_dell_dock_ec_write_fw (FuDevice *device, GBytes *blob_fw, g_return_val_if_fail (blob_fw != NULL, FALSE); dynamic_version = g_strndup ((gchar *) data + self->blob_version_offset, 11); - g_debug ("Writing firmware version %s", dynamic_version); + g_debug ("writing EC firmware version %s", dynamic_version); if (!fu_dell_dock_ec_modify_lock (device, self->unlock_target, TRUE, error)) return FALSE; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index a1417466c..d7371604b 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -795,7 +795,7 @@ fu_dell_dock_mst_write_fw (FuDevice *device, data[self->blob_major_offset], data[self->blob_minor_offset], data[self->blob_build_offset]); - g_debug ("Writing firmware version %s", dynamic_version); + g_debug ("writing MST firmware version %s", dynamic_version); /* determine the flash order */ if (!fu_dell_dock_mst_query_active_bank (self->symbiote, &bank_in_use, error)) diff --git a/plugins/dell-dock/fu-dell-dock-status.c b/plugins/dell-dock/fu-dell-dock-status.c index 8061c0419..478ed0a08 100644 --- a/plugins/dell-dock/fu-dell-dock-status.c +++ b/plugins/dell-dock/fu-dell-dock-status.c @@ -72,7 +72,7 @@ fu_dell_dock_status_write (FuDevice *device, memcpy (&status_version, data + self->blob_version_offset, sizeof (guint32)); dynamic_version = fu_dell_dock_status_ver_string (status_version); - g_debug ("Writing firmware version %s", dynamic_version); + g_debug ("writing status firmware version %s", dynamic_version); parent = fu_device_get_parent (device); if (!fu_dell_dock_ec_commit_package (parent, blob_fw, error)) From 3c8ada3f80b8fc7dd463fabf819fb8c5994cd135 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 12 Oct 2018 10:08:58 +0100 Subject: [PATCH 015/254] Don't segfault if a plugin returns FALSE from UpdateFunc with no error set This is clearly a plugin bug that needs fixing, but exploding in a ball of flames is not what anybody wants to see. --- src/fu-plugin.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fu-plugin.c b/src/fu-plugin.c index 83bd8c446..b5af82f4c 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -1409,6 +1409,15 @@ fu_plugin_runner_update (FuPlugin *self, history = fu_history_new (); device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL); if (!update_func (self, device, blob_fw, flags, &error_update)) { + if (error_update == NULL) { + g_critical ("plugin %s returned FALSE from UpdateFunc " + "but did not set error!", + fu_plugin_get_name (self)); + g_set_error_literal (&error_update, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } fu_device_set_update_error (device, error_update->message); g_propagate_error (error, error_update); return FALSE; From c9a7541120f256b38285938f778f9fac2fd72d49 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 12 Oct 2018 08:37:05 -0500 Subject: [PATCH 016/254] trivial: bump master to 1.2.0 This is a little unusual since 1.1.3 was never in master, only in 1_1_X. --- RELEASE | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE b/RELEASE index 556233b60..68ae8f76e 100644 --- a/RELEASE +++ b/RELEASE @@ -4,7 +4,7 @@ fwupd Release Notes git shortlog 1.1.2.. | grep -i -v trivial | grep -v Merge > NEWS.new -Version 1.1.3 +Version 1.2.0 ~~~~~~~~~~~~~ Released: 2018-xx-xx @@ -24,7 +24,7 @@ git add ../po/*.po 2. Commit changes to git: # MAKE SURE THESE ARE CORRECT -export release_ver="1.1.3" +export release_ver="1.2.0" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/meson.build b/meson.build index 20dbdba8f..96d752aea 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.1.3', + version : '1.2.0', license : 'LGPL-2.1+', meson_version : '>=0.43.0', default_options : ['warning_level=2', 'c_std=c99'], From 3e54789ee36db3b502b354ff3dfcf257cd0efc1e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 12 Oct 2018 08:41:41 -0500 Subject: [PATCH 017/254] trivial: snap: Swap the type of snap/snapcraft.yaml to be a real file Workaround for https://bugs.launchpad.net/launchpad/+bug/1797366 It was previously a symlink to contrib/snap/snapcraft-stable.yaml however infrastructure changes in launchpad have caused this to break automatic snap builds. --- contrib/snap/snapcraft-stable.yaml | 338 +---------------------------- snap/snapcraft.yaml | 338 ++++++++++++++++++++++++++++- 2 files changed, 338 insertions(+), 338 deletions(-) mode change 100644 => 120000 contrib/snap/snapcraft-stable.yaml mode change 120000 => 100644 snap/snapcraft.yaml diff --git a/contrib/snap/snapcraft-stable.yaml b/contrib/snap/snapcraft-stable.yaml deleted file mode 100644 index 4537a1167..000000000 --- a/contrib/snap/snapcraft-stable.yaml +++ /dev/null @@ -1,337 +0,0 @@ -name: fwupd -version-script: cat $SNAPCRAFT_STAGE/version -version: 'daily' -summary: A standalone version of fwupd to install newer firmware updates -description: | - This is a tool that can be used to install firmware updates on devices - not yet supported by the version of fwupd distributed with the OS. - -grade: stable -confinement: classic - -architectures: - - amd64 - -apps: - dfu-tool: - command: dfu-tool.wrapper - fwupdtool: - command: fwupdtool.wrapper - completer: - share/bash-completion/completions/fwupdtool - fwupd: - command: fwupd.wrapper - daemon: simple - fwupdmgr: - command: fwupdmgr.wrapper - completer: - share/bash-completion/completions/fwupdmgr - -parts: - libefivar-dev: - plugin: make - make-parameters: - - prefix=/ - - libdir=/lib - source: https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2 - build-packages: - - libpopt-dev - prime: - - -include - - -bin - - -share/man - - -lib/pkgconfig - #adjust the paths from libefivar - libefivar-fixpkgconfig: - plugin: make - source: contrib/snap/libefivar-fixpkgconfig - make-parameters: - - SNAPCRAFT_STAGE=$SNAPCRAFT_STAGE - after: [libefivar-dev] - libsmbios: - plugin: autotools - source: https://github.com/dell/libsmbios/archive/v2.4.2.tar.gz - build-packages: - - libxml2-dev - - pkg-config - - autoconf - - automake - - libtool - - autopoint - prime: - - -include/ - - -lib/pkgconfig - - -lib/python3.5 - - -sbin/ - - -share/ - - -etc/ - - -lib/*.a - meson: - plugin: python - source: https://github.com/mesonbuild/meson/releases/download/0.46.1/meson-0.46.1.tar.gz - build-packages: - - ninja-build - prime: - - -bin - - -etc - - -lib - - -share - - -usr - appstream-glib-dev: - plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false, -Dman=false, -Drpm=false] - source: https://github.com/hughsie/appstream-glib/archive/appstream_glib_0_7_9.tar.gz - build-packages: - - python3-pip - - gperf - - intltool - - libarchive-dev - - libgcab-dev - - libgdk-pixbuf2.0-dev - - libgirepository1.0-dev - - libglib2.0-dev - - libgtk-3-dev - - libjson-glib-dev - - libsoup2.4-dev - - libsqlite3-dev - - libyaml-dev - - libstemmer-dev - - uuid-dev - stage-packages: - - libarchive13 - - libgcab-1.0-0 - - libsoup2.4-1 - - libstemmer0d - - libgdk-pixbuf2.0-0 - prime: - - -usr/bin - - -usr/include - - -usr/share/doc - - -usr/lib/*/asb-plugins-5 - - -usr/share/bash-completion - - -usr/share/aclocal - - -usr/lib/*/pkgconfig - - -usr/share/installed-tests - - -usr/lib/systemd - - -usr/lib/glib-networking - - -usr/lib/dconf - - -usr/share/X11 - - -usr/share/GConf - - -usr/share/dbus-1 - - -usr/share/glib-2.0/schemas - - -usr/share/lintian - - -usr/share/man - - -usr/lib/*/gdk-pixbuf-2.0 - - -usr/share/gettext - after: [meson] - gudev: - plugin: autotools - source: https://github.com/GNOME/libgudev/archive/232.tar.gz - configflags: - - --disable-umockdev - build-packages: - - libglib2.0-dev - - pkg-config - - libudev-dev - - gtk-doc-tools - - gnome-common - prime: - - -include - - -lib/girepository-1.0 - - -lib/pkgconfig - - -share/ - libusb: - plugin: autotools - source: https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2 - configflags: - - --disable-static - prime: - - -include/ - - -lib/pkgconfig - gusb: - plugin: meson - source: https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz - meson-parameters: [--prefix=/, - -Dtests=false, - -Dvapi=false, - -Ddocs=false] - build-packages: - - libgirepository1.0-dev - prime: - - -bin/ - - -include - - -share - - -lib/*/pkgconfig - - -lib/*/girepository-1.0 - after: [meson, libusb] - gnu-efi: - plugin: make - source: http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.5.tar.bz2 - make-parameters: - - PREFIX=/usr - make-install-var: INSTALLROOT - prime: - - -usr/include/ - - -usr/lib - #fetch the latest version of the signed bootloader - #this might not match our fwupdx64.efi, but it's better than nothing - fwup-efi-signed: - build-packages: - - python3-apt - plugin: make - source: contrib/snap/fwup-efi-signed - #needed for UEFI plugin to build UX labels - build-introspection: - plugin: nil - stage-packages: - - python3-gi - - python3-gi-cairo - - python3-pil - prime: - - -etc - - -usr - - -lib - - -var - #0.19.8.1 adds support for GETTEXTDATADIRS which is needed by meson's msgfmthelper - gettext: - source: https://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.8.1.tar.xz - plugin: autotools - build-packages: - - bison - - libunistring-dev - - libxml2-dev - configflags: - - --prefix=/usr - - --disable-static - - --disable-curses - - --disable-java - - --enable-relocatable - - --without-emacs - - --without-included-glib - - --without-included-libunistring - - --without-included-libxml - stage-packages: - - libunistring0 - - libxml2 - - libgomp1 - prime: - - -**/*.a - - -**/*.la - - -usr/bin - - -usr/include - - -usr/lib/gettext - - -usr/share - fwupd: - plugin: meson - meson-parameters: [--prefix=/, - -Defi-includedir=$SNAPCRAFT_STAGE/usr/include/efi, - -Defi-ldsdir=$SNAPCRAFT_STAGE/usr/lib, - -Defi-libdir=$SNAPCRAFT_STAGE/usr/lib, - -Dtests=false, - -Ddaemon=true, - -Dgtkdoc=false, - -Dintrospection=false, - -Dman=false, - -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, - -Dpkcs7=false] - source: . - source-type: git - override-build: | - snapcraftctl build - echo $(git describe HEAD --always) > $SNAPCRAFT_STAGE/version - build-packages: - - bash-completion - - gcab - - gnutls-dev - - libarchive-dev - - libcairo-dev - - libelf-dev - - libgcab-dev - - libglib2.0-dev - - libgpgme11-dev - - libjson-glib-dev - - libpango1.0-dev - - libpolkit-gobject-1-dev - - libsoup2.4-dev - - libsqlite3-dev - - locales - - pkg-config - - uuid-dev - stage-packages: - - libgcab-1.0-0 - - libarchive13 - - libassuan0 - - liblcms2-2 - - libelf1 - - libgpgme11 - - libjson-glib-1.0-0 - - libpolkit-gobject-1-0 - - libsoup2.4-1 - - glib-networking - - libglib2.0-bin - prime: - # we explicitly don't want /usr/bin/gpgconf - # this will cause gpgme to error finding it - # but that also avoids trying to use non-existent - # /usr/bin/gpg2 - - -usr/bin - - -usr/sbin - - -usr/share/man - - -usr/share/GConf - - -etc/X11 - - -etc/ldap - - -etc/logcheck - - -usr/lib/dconf - - -usr/lib/gcc - - -usr/lib/glib-networking - - -usr/lib/gnupg2 - - -usr/lib/sasl2 - - -usr/lib/systemd - - -usr/lib/*/audit - - -usr/share/glib-2.0/schemas - - -usr/share/X11 - - -include - - -lib/systemd - - -lib/udev - - -lib/*/pkgconfig - - -usr/share/lintian - - -usr/share/pkgconfig - - -usr/share/installed-tests - - -usr/share/polkit-1 - - -usr/share/vala - - -usr/share/doc - - -usr/share/gnupg2 - - -usr/share/info - - -usr/share/gir-1.0 - - -usr/share/upstart - - -usr/lib/*/pkgconfig - after: [appstream-glib-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] - fix-bash-completion: - plugin: make - source: contrib/snap/fix-bash-completion - after: [fwupd] - update-mime: - plugin: make - source: contrib/snap/update-mime - stage-packages: - - shared-mime-info - - gsettings-desktop-schemas - - libxml2 - prime: - - -usr/bin - - -usr/share/doc - - -usr/share/doc-base - - -usr/share/man - - -usr/share/lintian - - -usr/share/pkgconfig - - -usr/share/GConf - after: [fwupd] - fwupd-wrappers: - plugin: dump - source: contrib/snap - stage: - - dfu-tool.wrapper - - fwupd-command - - fwupdtool.wrapper - - fwupd.wrapper - - fwupdmgr.wrapper diff --git a/contrib/snap/snapcraft-stable.yaml b/contrib/snap/snapcraft-stable.yaml new file mode 120000 index 000000000..8eb2a570d --- /dev/null +++ b/contrib/snap/snapcraft-stable.yaml @@ -0,0 +1 @@ +../../snap/snapcraft.yaml \ No newline at end of file diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml deleted file mode 120000 index 25d9b6844..000000000 --- a/snap/snapcraft.yaml +++ /dev/null @@ -1 +0,0 @@ -../contrib/snap/snapcraft-stable.yaml \ No newline at end of file diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 000000000..4537a1167 --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,337 @@ +name: fwupd +version-script: cat $SNAPCRAFT_STAGE/version +version: 'daily' +summary: A standalone version of fwupd to install newer firmware updates +description: | + This is a tool that can be used to install firmware updates on devices + not yet supported by the version of fwupd distributed with the OS. + +grade: stable +confinement: classic + +architectures: + - amd64 + +apps: + dfu-tool: + command: dfu-tool.wrapper + fwupdtool: + command: fwupdtool.wrapper + completer: + share/bash-completion/completions/fwupdtool + fwupd: + command: fwupd.wrapper + daemon: simple + fwupdmgr: + command: fwupdmgr.wrapper + completer: + share/bash-completion/completions/fwupdmgr + +parts: + libefivar-dev: + plugin: make + make-parameters: + - prefix=/ + - libdir=/lib + source: https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2 + build-packages: + - libpopt-dev + prime: + - -include + - -bin + - -share/man + - -lib/pkgconfig + #adjust the paths from libefivar + libefivar-fixpkgconfig: + plugin: make + source: contrib/snap/libefivar-fixpkgconfig + make-parameters: + - SNAPCRAFT_STAGE=$SNAPCRAFT_STAGE + after: [libefivar-dev] + libsmbios: + plugin: autotools + source: https://github.com/dell/libsmbios/archive/v2.4.2.tar.gz + build-packages: + - libxml2-dev + - pkg-config + - autoconf + - automake + - libtool + - autopoint + prime: + - -include/ + - -lib/pkgconfig + - -lib/python3.5 + - -sbin/ + - -share/ + - -etc/ + - -lib/*.a + meson: + plugin: python + source: https://github.com/mesonbuild/meson/releases/download/0.46.1/meson-0.46.1.tar.gz + build-packages: + - ninja-build + prime: + - -bin + - -etc + - -lib + - -share + - -usr + appstream-glib-dev: + plugin: meson + meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false, -Dman=false, -Drpm=false] + source: https://github.com/hughsie/appstream-glib/archive/appstream_glib_0_7_9.tar.gz + build-packages: + - python3-pip + - gperf + - intltool + - libarchive-dev + - libgcab-dev + - libgdk-pixbuf2.0-dev + - libgirepository1.0-dev + - libglib2.0-dev + - libgtk-3-dev + - libjson-glib-dev + - libsoup2.4-dev + - libsqlite3-dev + - libyaml-dev + - libstemmer-dev + - uuid-dev + stage-packages: + - libarchive13 + - libgcab-1.0-0 + - libsoup2.4-1 + - libstemmer0d + - libgdk-pixbuf2.0-0 + prime: + - -usr/bin + - -usr/include + - -usr/share/doc + - -usr/lib/*/asb-plugins-5 + - -usr/share/bash-completion + - -usr/share/aclocal + - -usr/lib/*/pkgconfig + - -usr/share/installed-tests + - -usr/lib/systemd + - -usr/lib/glib-networking + - -usr/lib/dconf + - -usr/share/X11 + - -usr/share/GConf + - -usr/share/dbus-1 + - -usr/share/glib-2.0/schemas + - -usr/share/lintian + - -usr/share/man + - -usr/lib/*/gdk-pixbuf-2.0 + - -usr/share/gettext + after: [meson] + gudev: + plugin: autotools + source: https://github.com/GNOME/libgudev/archive/232.tar.gz + configflags: + - --disable-umockdev + build-packages: + - libglib2.0-dev + - pkg-config + - libudev-dev + - gtk-doc-tools + - gnome-common + prime: + - -include + - -lib/girepository-1.0 + - -lib/pkgconfig + - -share/ + libusb: + plugin: autotools + source: https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2 + configflags: + - --disable-static + prime: + - -include/ + - -lib/pkgconfig + gusb: + plugin: meson + source: https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz + meson-parameters: [--prefix=/, + -Dtests=false, + -Dvapi=false, + -Ddocs=false] + build-packages: + - libgirepository1.0-dev + prime: + - -bin/ + - -include + - -share + - -lib/*/pkgconfig + - -lib/*/girepository-1.0 + after: [meson, libusb] + gnu-efi: + plugin: make + source: http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.5.tar.bz2 + make-parameters: + - PREFIX=/usr + make-install-var: INSTALLROOT + prime: + - -usr/include/ + - -usr/lib + #fetch the latest version of the signed bootloader + #this might not match our fwupdx64.efi, but it's better than nothing + fwup-efi-signed: + build-packages: + - python3-apt + plugin: make + source: contrib/snap/fwup-efi-signed + #needed for UEFI plugin to build UX labels + build-introspection: + plugin: nil + stage-packages: + - python3-gi + - python3-gi-cairo + - python3-pil + prime: + - -etc + - -usr + - -lib + - -var + #0.19.8.1 adds support for GETTEXTDATADIRS which is needed by meson's msgfmthelper + gettext: + source: https://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.8.1.tar.xz + plugin: autotools + build-packages: + - bison + - libunistring-dev + - libxml2-dev + configflags: + - --prefix=/usr + - --disable-static + - --disable-curses + - --disable-java + - --enable-relocatable + - --without-emacs + - --without-included-glib + - --without-included-libunistring + - --without-included-libxml + stage-packages: + - libunistring0 + - libxml2 + - libgomp1 + prime: + - -**/*.a + - -**/*.la + - -usr/bin + - -usr/include + - -usr/lib/gettext + - -usr/share + fwupd: + plugin: meson + meson-parameters: [--prefix=/, + -Defi-includedir=$SNAPCRAFT_STAGE/usr/include/efi, + -Defi-ldsdir=$SNAPCRAFT_STAGE/usr/lib, + -Defi-libdir=$SNAPCRAFT_STAGE/usr/lib, + -Dtests=false, + -Ddaemon=true, + -Dgtkdoc=false, + -Dintrospection=false, + -Dman=false, + -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + -Dpkcs7=false] + source: . + source-type: git + override-build: | + snapcraftctl build + echo $(git describe HEAD --always) > $SNAPCRAFT_STAGE/version + build-packages: + - bash-completion + - gcab + - gnutls-dev + - libarchive-dev + - libcairo-dev + - libelf-dev + - libgcab-dev + - libglib2.0-dev + - libgpgme11-dev + - libjson-glib-dev + - libpango1.0-dev + - libpolkit-gobject-1-dev + - libsoup2.4-dev + - libsqlite3-dev + - locales + - pkg-config + - uuid-dev + stage-packages: + - libgcab-1.0-0 + - libarchive13 + - libassuan0 + - liblcms2-2 + - libelf1 + - libgpgme11 + - libjson-glib-1.0-0 + - libpolkit-gobject-1-0 + - libsoup2.4-1 + - glib-networking + - libglib2.0-bin + prime: + # we explicitly don't want /usr/bin/gpgconf + # this will cause gpgme to error finding it + # but that also avoids trying to use non-existent + # /usr/bin/gpg2 + - -usr/bin + - -usr/sbin + - -usr/share/man + - -usr/share/GConf + - -etc/X11 + - -etc/ldap + - -etc/logcheck + - -usr/lib/dconf + - -usr/lib/gcc + - -usr/lib/glib-networking + - -usr/lib/gnupg2 + - -usr/lib/sasl2 + - -usr/lib/systemd + - -usr/lib/*/audit + - -usr/share/glib-2.0/schemas + - -usr/share/X11 + - -include + - -lib/systemd + - -lib/udev + - -lib/*/pkgconfig + - -usr/share/lintian + - -usr/share/pkgconfig + - -usr/share/installed-tests + - -usr/share/polkit-1 + - -usr/share/vala + - -usr/share/doc + - -usr/share/gnupg2 + - -usr/share/info + - -usr/share/gir-1.0 + - -usr/share/upstart + - -usr/lib/*/pkgconfig + after: [appstream-glib-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] + fix-bash-completion: + plugin: make + source: contrib/snap/fix-bash-completion + after: [fwupd] + update-mime: + plugin: make + source: contrib/snap/update-mime + stage-packages: + - shared-mime-info + - gsettings-desktop-schemas + - libxml2 + prime: + - -usr/bin + - -usr/share/doc + - -usr/share/doc-base + - -usr/share/man + - -usr/share/lintian + - -usr/share/pkgconfig + - -usr/share/GConf + after: [fwupd] + fwupd-wrappers: + plugin: dump + source: contrib/snap + stage: + - dfu-tool.wrapper + - fwupd-command + - fwupdtool.wrapper + - fwupd.wrapper + - fwupdmgr.wrapper From 802a279bd2b53e59f1d1d363c2d106e59b59b6fb Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 12 Oct 2018 11:59:04 -0500 Subject: [PATCH 018/254] trivial: snap: drop the stable symlink Leading to this problem: Building fwupd-wrappers Failed to copy '/build/fwupd/parts/fwupd-wrappers/build/snapcraft-stable.yaml': it's a symlink pointing outside the snap. Fix it to be valid when snapped and try again. Build failed Traceback (most recent call last): File "/usr/lib/python2.7/dist-packages/lpbuildd/target/build_snap.py", line 229, in run self.build() File "/usr/lib/python2.7/dist-packages/lpbuildd/target/build_snap.py", line 218, in build env=env) File "/usr/lib/python2.7/dist-packages/lpbuildd/target/build_snap.py", line 75, in run_build_command return self.backend.run(args, env=full_env, **kwargs) File "/usr/lib/python2.7/dist-packages/lpbuildd/target/lxd.py", line 460, in run subprocess.check_call(cmd, **kwargs) File "/usr/lib/python2.7/subprocess.py", line 541, in check_call raise CalledProcessError(retcode, cmd) Scanning for processes to kill in build SNAPBUILD-351860 --- contrib/snap/snapcraft-stable.yaml | 1 - 1 file changed, 1 deletion(-) delete mode 120000 contrib/snap/snapcraft-stable.yaml diff --git a/contrib/snap/snapcraft-stable.yaml b/contrib/snap/snapcraft-stable.yaml deleted file mode 120000 index 8eb2a570d..000000000 --- a/contrib/snap/snapcraft-stable.yaml +++ /dev/null @@ -1 +0,0 @@ -../../snap/snapcraft.yaml \ No newline at end of file From 4bd12b376a157d49b9892fdb3d5468f83faf6ee3 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 12 Oct 2018 11:05:58 -0500 Subject: [PATCH 019/254] dell-dock: Correct a situation that error wasn't propagating This code was from an earlier instance that had special fallbacks and error_local wasn't removed. --- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index d7371604b..4811a1c64 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -162,20 +162,18 @@ fu_dell_dock_mst_read_register (FuDevice *symbiote, GBytes **bytes, GError **error) { - g_autoptr(GError) error_local = NULL; - g_return_val_if_fail (symbiote != NULL, FALSE); g_return_val_if_fail (bytes != NULL, FALSE); g_return_val_if_fail (length <= 32, FALSE); /* write the offset we're querying */ if (!fu_dell_dock_hid_i2c_write (symbiote, (guint8 *) &address, 4, - &mst_base_settings, &error_local)) + &mst_base_settings, error)) return FALSE; /* read data for the result */ if (!fu_dell_dock_hid_i2c_read (symbiote, 0, length, bytes, - &mst_base_settings, &error_local)) + &mst_base_settings, error)) return FALSE; return TRUE; @@ -188,7 +186,6 @@ fu_dell_dock_mst_write_register (FuDevice *symbiote, gsize length, GError **error) { - g_autoptr(GError) error_local = NULL; g_autofree guint8 *buffer = g_malloc0 (length + 4); memcpy (buffer, &address, 4); memcpy (buffer + 4, data, length); @@ -198,7 +195,7 @@ fu_dell_dock_mst_write_register (FuDevice *symbiote, /* write the offset we're querying */ return fu_dell_dock_hid_i2c_write (symbiote, buffer, length + 4, - &mst_base_settings, &error_local); + &mst_base_settings, error); } static gboolean From 327c37d58e1ed25b41bff79491cca48ca86bcf4c Mon Sep 17 00:00:00 2001 From: Abhijeet Sharma Date: Sun, 14 Oct 2018 05:55:50 +0530 Subject: [PATCH 020/254] Readme Updated: Added KDE Discover as one more graphical front-end available for fwupd. --- README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 00c2567f2..6469d29c4 100644 --- a/README.md +++ b/README.md @@ -73,14 +73,19 @@ To clear the local history of updates: Other frontends ------------------- -Currently [GNOME Software](https://wiki.gnome.org/Apps/Software) is the only graphical -frontend available. When compiled with firmware support, it will check for updates -periodically and automatically download firmware in the background. + 1. [GNOME Software](https://wiki.gnome.org/Apps/Software) is the graphical + frontend available. When compiled with firmware support, it will check for + updates periodically and automatically download firmware in the background. + After the firmware has been downloaded a popup will be displayed in Gnome + Software to perform the update. -After the firmware has been downloaded a popup will be displayed in Gnome Software -to perform the update. +2. [KDE Discover](https://userbase.kde.org/Discover) is the software centre, + generally bundled with KDE Plasma. With the release of + [KDE Plasma 5.14](https://www.kde.org/announcements/plasma-5.14.0.php), + a new fwupd backend has been implemented in KDE Discover for firmware updates. + These firmware updates are shown with other system updates. -On Dell IoT gateways, [Wyse Cloud Client Manager (CCM)](http://www.dell.com/us/business/p/wyse-cloud-client-manager/pd) -has been built with fwupd support. -The remote administration interface can be used to download and deploy -firmware updates. +3. [Wyse Cloud Client Manager (CCM)](http://www.dell.com/us/business/p/wyse-cloud-client-manager/pd) + A software suite available on Dell IoT gateways with built-in fwupd support. + The remote administration interface can be used to download and deploy firmware + updates. From 860e99357beb8fdf28b7697f196660599cc07ede Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Sat, 13 Oct 2018 14:12:08 -0500 Subject: [PATCH 021/254] dell-dock: If marketing name is invalid don't fail initialization These are certainly bugs with one of the components, but if the situation happens in the field the plugin needs to finish initialization to allow upgrading to a fixed component. We'll just fall back to the name in the quirk (Dell dock) in this case. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 18b431207..bcacd6b76 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -414,12 +414,14 @@ fu_dell_dock_ec_get_dock_data (FuDevice *device, /* guard against EC not yet ready and fail init */ name = g_string_new (self->data->marketing_name); - if (name->len == 0) { - g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, - "Invalid name detected, dock may be booting up"); - return FALSE; - } - fu_device_set_name (device, name->str); + if (name->len > 0) + fu_device_set_name (device, name->str); + else + g_warning ("[EC bug] Invalid dock name detected"); + + if (self->data->module_type >= 0xfe) + g_warning ("[EC bug] Invalid module type 0x%02x", + self->data->module_type); /* set serial number */ memcpy (service_tag, self->data->service_tag, 7); From 7e5c6eebfebd1f69a87a43a1cf987f465d5800b6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 15 Oct 2018 16:28:27 -0500 Subject: [PATCH 022/254] meson: Bump dependency to 0.44 and adjust sysconfdir handling Some code was put in place to workaround sysconfdir behavior of meson 0.43 and less. This is no longer needed. --- data/meson.build | 2 +- meson.build | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/data/meson.build b/data/meson.build index 4f7c9c4d7..8dd2ac9ad 100644 --- a/data/meson.build +++ b/data/meson.build @@ -38,7 +38,7 @@ if get_option('systemd') rw_directories = [] rw_directories += join_paths (localstatedir, 'lib', 'fwupd') - rw_directories += join_paths (default_sysconfdir, 'fwupd', 'remotes.d') + rw_directories += join_paths (sysconfdir, 'fwupd', 'remotes.d') if get_option('plugin_uefi') rw_directories += ['-/boot/efi', '-/efi/EFI', '-/boot/EFI'] endif diff --git a/meson.build b/meson.build index 96d752aea..1f143c9d4 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('fwupd', 'c', version : '1.2.0', license : 'LGPL-2.1+', - meson_version : '>=0.43.0', + meson_version : '>=0.44.0', default_options : ['warning_level=2', 'c_std=c99'], ) @@ -310,12 +310,6 @@ configure_file( configuration : conf ) -default_sysconfdir = get_option('sysconfdir') -if default_sysconfdir == 'etc' - message('sysconfdir of etc makes no sense, using /etc') - default_sysconfdir = '/etc' -endif - plugin_deps = [] plugin_deps += appstream_glib plugin_deps += gio From e61c94dd25f145bdb4e62f57d9876cb0b8d65117 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 11 Oct 2018 10:49:55 -0500 Subject: [PATCH 023/254] fu-tool: Stop any running daemon over dbus before loading engine This helps to prevent conflicts of the daemon trying to claim devices at the same time as the tool. --- src/fu-tool.c | 75 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index 138094337..5cfa65b54 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -23,6 +23,11 @@ #include "fu-util-common.h" #include "fu-debug.h" +#define SYSTEMD_SERVICE "org.freedesktop.systemd1" +#define SYSTEMD_OBJECT_PATH "/org/freedesktop/systemd1" +#define SYSTEMD_MANAGER_INTERFACE "org.freedesktop.systemd1.Manager" +#define SYSTEMD_FWUPD_UNIT "fwupd.service" + /* this is only valid in this file */ #define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) @@ -62,6 +67,60 @@ fu_util_item_free (FuUtilItem *item) g_free (item); } +static gboolean +fu_util_start_engine (FuUtilPrivate *priv, GError **error) +{ +#ifdef HAVE_SYSTEMD + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(GError) error_local = NULL; + + /* try to stop any already running daemon */ + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + SYSTEMD_SERVICE, + SYSTEMD_OBJECT_PATH, + SYSTEMD_MANAGER_INTERFACE, + NULL, + error); + if (proxy == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy, + "GetUnit", + g_variant_new ("(s)", + SYSTEMD_FWUPD_UNIT), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error_local); + if (val == NULL) { + g_debug ("Unable to find %s: %s", + SYSTEMD_FWUPD_UNIT, + error_local->message); + } else { + g_clear_object (&val); + val = g_dbus_proxy_call_sync (proxy, + "StopUnit", + g_variant_new ("(ss)", + SYSTEMD_FWUPD_UNIT, + "replace"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); + if (val == NULL) + return FALSE; + } + +#endif + return fu_engine_load (priv->engine, error); +} + static gint fu_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2) { @@ -270,7 +329,7 @@ fu_main_engine_percentage_changed_cb (FuEngine *engine, static gboolean fu_util_watch (FuUtilPrivate *priv, gchar **values, GError **error) { - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; g_main_loop_run (priv->loop); return TRUE; @@ -318,7 +377,7 @@ fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) gint fd; /* load engine */ - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; /* check args */ @@ -361,7 +420,7 @@ fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(GPtrArray) devs = NULL; /* load engine */ - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; /* print */ @@ -406,7 +465,7 @@ fu_util_get_topology (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(GPtrArray) devs = NULL; /* load engine */ - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; /* print */ @@ -512,7 +571,7 @@ fu_util_install_blob (FuUtilPrivate *priv, gchar **values, GError **error) } /* load engine */ - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; /* get device */ @@ -599,7 +658,7 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(GPtrArray) install_tasks = NULL; /* load engine */ - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; /* handle both forms */ @@ -697,7 +756,7 @@ fu_util_detach (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(FuDeviceLocker) locker = NULL; /* load engine */ - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; /* invalid args */ @@ -734,7 +793,7 @@ fu_util_attach (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(FuDeviceLocker) locker = NULL; /* load engine */ - if (!fu_engine_load (priv->engine, error)) + if (!fu_util_start_engine (priv, error)) return FALSE; /* invalid args */ From 6754f5aa70bb470364ec6c774257ac6cacd0dbb8 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 11 Oct 2018 10:50:03 -0500 Subject: [PATCH 024/254] fu-main: Catch SIGTERM while update is in progress This prevents systemd from stopping while a firmware update is in progress. --- src/fu-main.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/fu-main.c b/src/fu-main.c index 9cb9530f0..4d36ec04f 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -43,8 +44,23 @@ typedef struct { PolkitAuthority *authority; guint owner_id; FuEngine *engine; + gboolean update_in_progress; + gboolean pending_sigterm; } FuMainPrivate; +static gboolean +fu_main_sigterm_cb (gpointer user_data) +{ + FuMainPrivate *priv = (FuMainPrivate *) user_data; + if (!priv->update_in_progress) { + g_main_loop_quit (priv->loop); + return G_SOURCE_REMOVE; + } + g_warning ("Received SIGTERM during a firmware update, ignoring"); + priv->pending_sigterm = TRUE; + return G_SOURCE_CONTINUE; +} + static void fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv) { @@ -447,6 +463,7 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) FuMainPrivate *priv = helper_ref->priv; g_autoptr(FuMainAuthHelper) helper = helper_ref; g_autoptr(GError) error = NULL; + gboolean ret; /* still more things to to authenticate */ if (helper->action_ids->len > 0) { @@ -463,11 +480,16 @@ fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) } /* all authenticated, so install all the things */ - if (!fu_engine_install_tasks (helper->priv->engine, - helper->install_tasks, - helper->blob_cab, - helper->flags, - &error)) { + priv->update_in_progress = TRUE; + ret = fu_engine_install_tasks (helper->priv->engine, + helper->install_tasks, + helper->blob_cab, + helper->flags, + &error); + priv->update_in_progress = FALSE; + if (priv->pending_sigterm) + g_main_loop_quit (priv->loop); + if (!ret) { g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } @@ -1267,6 +1289,10 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + g_unix_signal_add_full (G_PRIORITY_DEFAULT, + SIGTERM, fu_main_sigterm_cb, + priv, NULL); + /* load introspection from file */ priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml", &error); From 5caffbfb9c9a39de8aaf523c13670a10df9496cf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 17 Oct 2018 09:56:11 +0100 Subject: [PATCH 025/254] Bump requirement to meson 0.46.0 --- meson.build | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index 1f143c9d4..04b1d4450 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('fwupd', 'c', version : '1.2.0', license : 'LGPL-2.1+', - meson_version : '>=0.44.0', + meson_version : '>=0.46.0', default_options : ['warning_level=2', 'c_std=c99'], ) @@ -114,14 +114,8 @@ test_link_args = [ '-Wl,-z,now', ] foreach arg: test_link_args - if meson.version().version_compare('>=0.46.0') - if cc.has_link_argument(arg) - global_link_args += arg - endif - else - if cc.has_argument(arg) - global_link_args += arg - endif + if cc.has_link_argument(arg) + global_link_args += arg endif endforeach add_global_link_arguments( From ef677dab81ca71141917f31baaf55535f5cc5632 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 15 Oct 2018 15:04:15 +0100 Subject: [PATCH 026/254] trivial: Rename a function to better explain what it does --- libfwupd/fwupd-common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index e2933a1e4..8e52bbb87 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -45,7 +45,7 @@ fwupd_checksum_guess_kind (const gchar *checksum) } static const gchar * -_g_checksum_type_to_string (GChecksumType checksum_type) +fwupd_checksum_type_to_string_display (GChecksumType checksum_type) { if (checksum_type == G_CHECKSUM_MD5) return "MD5"; @@ -72,7 +72,9 @@ gchar * fwupd_checksum_format_for_display (const gchar *checksum) { GChecksumType kind = fwupd_checksum_guess_kind (checksum); - return g_strdup_printf ("%s(%s)", _g_checksum_type_to_string (kind), checksum); + return g_strdup_printf ("%s(%s)", + fwupd_checksum_type_to_string_display (kind), + checksum); } /** From 481aa2a923c21498908dd1a17748c416213218a8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Sep 2018 20:51:46 +0100 Subject: [PATCH 027/254] Port from libappstream-glib to libxmlb The libxmlb library is much faster to query, and does not require the daemon to parse the XML metadata at startup. It's a zero-copy mmap design that is more modern and less clunky. RSS has reduced from 3Mb (peak 3.61Mb) to 1Mb (peak 1.07Mb) and the startup time has gone from 280ms to 250ms. --- .gitignore | 1 + contrib/PKGBUILD | 4 +- contrib/ci/Dockerfile-centos.in | 1 - contrib/ci/Dockerfile-fedora.in | 1 + contrib/ci/debian_s390x.sh | 2 + contrib/ci/dependencies.xml | 58 +- contrib/debian/gir1.2-fwupd-2.0.install | 2 +- contrib/debian/libfwupd-dev.install | 9 +- contrib/debian/libfwupd2.install | 2 +- contrib/debian/rules | 10 +- contrib/debian/source/lintian-overrides | 2 + contrib/fwupd.spec.in | 7 +- contrib/org.freedesktop.fwupd.json | 21 + contrib/snap/snapcraft-master.yaml | 24 +- meson.build | 4 +- plugins/dell-dock/fu-dell-dock-hub.c | 2 - plugins/dell-dock/fu-dell-dock-i2c-ec.c | 8 +- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 1 - plugins/dell-dock/fu-dell-dock-status.c | 1 - plugins/dfu/meson.build | 5 +- plugins/uefi/meson.build | 2 +- plugins/wacomhid/meson.build | 2 +- snap/snapcraft.yaml | 24 +- src/fu-common-cab.c | 346 ++++--- src/fu-common-cab.h | 4 +- src/fu-config.c | 151 ++- src/fu-engine.c | 1197 +++++++++++----------- src/fu-engine.h | 10 +- src/fu-install-task.c | 46 +- src/fu-install-task.h | 6 +- src/fu-keyring-utils.c | 36 +- src/fu-keyring-utils.h | 4 +- src/fu-main.c | 32 +- src/fu-plugin.h | 1 - src/fu-self-test.c | 451 ++++---- src/fu-tool.c | 24 +- src/fu-util.c | 64 +- src/meson.build | 12 +- subprojects/.gitignore | 1 + subprojects/libxmlb.wrap | 4 + 40 files changed, 1404 insertions(+), 1178 deletions(-) create mode 100644 subprojects/.gitignore create mode 100644 subprojects/libxmlb.wrap diff --git a/.gitignore b/.gitignore index 2ffc0c825..d5a589422 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /prime /stage /snap/.snapcraft +/libxmlb /*.deb /*.ddeb /*.changes diff --git a/contrib/PKGBUILD b/contrib/PKGBUILD index 3e0d6f032..6600a46eb 100644 --- a/contrib/PKGBUILD +++ b/contrib/PKGBUILD @@ -8,7 +8,7 @@ pkgdesc='A simple daemon to allow session software to update firmware' arch=('i686' 'x86_64') url='https://github.com/hughsie/fwupd' license=('GPL2') -depends=('appstream-glib' 'libgusb') +depends=('libgusb') makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow' 'git' 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala' 'libsoup' 'polkit' 'gcab') @@ -16,7 +16,7 @@ makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow build() { cd ${pkgname} if [ -n "$CI" ]; then - export CI="--werror" + export CI="--werror --wrap-mode=forcefallback" fi arch-meson -D b_lto=false $CI ../build diff --git a/contrib/ci/Dockerfile-centos.in b/contrib/ci/Dockerfile-centos.in index 76fabcc2c..cd79a76f9 100644 --- a/contrib/ci/Dockerfile-centos.in +++ b/contrib/ci/Dockerfile-centos.in @@ -7,7 +7,6 @@ RUN echo fubar > /etc/machine-id RUN yum install epel-release -y RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% -RUN yum install -y https://kojipkgs.fedoraproject.org//packages/libstemmer/0/10.585svn.fc29/x86_64/libstemmer-0-10.585svn.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libappstream-glib/0.7.7/3.fc29/x86_64/libappstream-glib-0.7.7-3.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libappstream-glib/0.7.7/3.fc29/x86_64/libappstream-glib-devel-0.7.7-3.fc29.x86_64.rpm RUN pip3 install pillow pygobject RUN wget https://copr.fedorainfracloud.org/coprs/jsynacek/systemd-backports-for-centos-7/repo/epel-7/jsynacek-systemd-backports-for-centos-7-epel-7.repo -O /etc/yum.repos.d/jsynacek-systemd-centos-7.repo RUN yum --enablerepo=epel-testing -y update diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index ec3d87b0d..09cdbae13 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -5,6 +5,7 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id RUN dnf --enablerepo=updates-testing -y update +RUN dnf install -y https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.2/1.fc29/x86_64/libxmlb-0.1.2-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.2/1.fc29/x86_64/libxmlb-devel-0.1.2-1.fc29.x86_64.rpm RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN mkdir /build diff --git a/contrib/ci/debian_s390x.sh b/contrib/ci/debian_s390x.sh index c65f877ae..25b31ba7a 100755 --- a/contrib/ci/debian_s390x.sh +++ b/contrib/ci/debian_s390x.sh @@ -16,6 +16,8 @@ meson .. \ -Dplugin_redfish=false \ -Dintrospection=false \ -Dgtkdoc=false \ + -Dlibxmlb:introspection=false \ + -Dlibxmlb:gtkdoc=false \ -Dman=false ninja -v ninja test -v diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index a2dbbec82..fc688fdaf 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -366,15 +366,6 @@ gnu-efi - - - - - - - - - @@ -551,31 +542,33 @@ - + libarchive-devel @@ -1052,6 +1045,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -1093,10 +1107,20 @@ - + libuuid-devel + + + + uuid-dev:s390x + + + + + + diff --git a/contrib/debian/gir1.2-fwupd-2.0.install b/contrib/debian/gir1.2-fwupd-2.0.install index 78a92bbc2..eee37f27b 100644 --- a/contrib/debian/gir1.2-fwupd-2.0.install +++ b/contrib/debian/gir1.2-fwupd-2.0.install @@ -1 +1 @@ -usr/lib/*/girepository-1.0/Fwupd-2.0.typelib +usr/lib/*/girepository-1.0/*.typelib diff --git a/contrib/debian/libfwupd-dev.install b/contrib/debian/libfwupd-dev.install index dbc3671c9..8691785f0 100644 --- a/contrib/debian/libfwupd-dev.install +++ b/contrib/debian/libfwupd-dev.install @@ -1,6 +1,5 @@ -usr/include/fwupd-1/fwupd.h -usr/include/fwupd-1/libfwupd -usr/lib/*/libfwupd*.so -usr/lib/*/pkgconfig/fwupd.pc -usr/share/gir-1.0/Fwupd*.gir +usr/include/* +usr/lib/*/*.so +usr/lib/*/pkgconfig/*.pc +usr/share/gir-1.0/*.gir usr/share/vala/vapi diff --git a/contrib/debian/libfwupd2.install b/contrib/debian/libfwupd2.install index 6467ff9e0..3de3b10a4 100644 --- a/contrib/debian/libfwupd2.install +++ b/contrib/debian/libfwupd2.install @@ -1 +1 @@ -usr/lib/*/libfwup*.so.* +usr/lib/*/*.so.* diff --git a/contrib/debian/rules b/contrib/debian/rules index 8eee89456..666cc6e34 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -10,7 +10,8 @@ ifeq "$(DEB_HOST_ARCH_BITS)" "32" endif ifneq ($(CI),) - export CI=--werror + export CI=--werror --wrap-mode=forcefallback + export DHSLIBS=-- --ignore-missing-info endif SB_STYLE := debian @@ -53,6 +54,10 @@ override_dh_install: dh_install -pfwupd usr/lib/fwupd/efi ;\ dh_install -pfwupd usr/lib/fwupd/fwupdate; \ fi + #if build with meson subproject in CI need to install this too + if [ -n "$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \ + dh_install -pfwupd usr/lib/xb-tool ;\ + fi dh_missing -a --fail-missing #this is placed in fwupd-tests @@ -91,3 +96,6 @@ ifeq (ubuntu,$(SB_STYLE)) dpkg-distaddfile $(tar_name) raw-uefi - ;\ fi endif + +override_dh_shlibdeps: + dh_shlibdeps $$DHSLIBS diff --git a/contrib/debian/source/lintian-overrides b/contrib/debian/source/lintian-overrides index 1e5cac9aa..e13407f37 100644 --- a/contrib/debian/source/lintian-overrides +++ b/contrib/debian/source/lintian-overrides @@ -1,2 +1,4 @@ #github doesn't have these fwupd source: debian-watch-does-not-check-gpg-signature +#to make CI happy until libxmlb lands +fwupd source: source-is-missing diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 6cef89193..06b72aafd 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -1,5 +1,5 @@ %global glib2_version 2.45.8 -%global libappstream_version 0.7.4 +%global libxmlb_version 0.1.2 %global libgusb_version 0.2.11 %global libsoup_version 2.51.92 %global systemd_version 231 @@ -36,7 +36,7 @@ Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}. BuildRequires: gettext BuildRequires: glib2-devel >= %{glib2_version} -BuildRequires: libappstream-glib-devel >= %{libappstream_version} +BuildRequires: libxmlb-devel >= %{libxmlb_version} BuildRequires: libgcab1-devel BuildRequires: libgudev1-devel BuildRequires: libgusb-devel >= %{libgusb_version} @@ -89,10 +89,11 @@ Requires(preun): systemd Requires(postun): systemd Requires: glib2%{?_isa} >= %{glib2_version} -Requires: libappstream-glib%{?_isa} >= %{libappstream_version} +Requires: libxmlb%{?_isa} >= %{libxmlb_version} Requires: libgusb%{?_isa} >= %{libgusb_version} Requires: libsoup%{?_isa} >= %{libsoup_version} Requires: bubblewrap +Requires: shared-mime-info Recommends: python3 diff --git a/contrib/org.freedesktop.fwupd.json b/contrib/org.freedesktop.fwupd.json index 8f63e2af7..6cfa67215 100644 --- a/contrib/org.freedesktop.fwupd.json +++ b/contrib/org.freedesktop.fwupd.json @@ -199,6 +199,27 @@ } ] }, + { + "name": "libxmlb", + "buildsystem": "meson", + "config-opts": [ + "-Dintrospection=false", + "-Dgtkdoc=false", + "-Dtests=false", + "--sysconfdir=/app/etc", + "--localstatedir=/var/data" + ], + "cleanup": [ + "/libexec/xb-tool" + ], + "sources": [ + { + "type": "archive", + "url": "https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.2.tar.xz", + "sha256": "20a734895830ae2af82a270b61e4832c6012b1aaf2003e1300d743dbd6aa95cf" + } + ] + }, { "name": "fwupd", "buildsystem": "meson", diff --git a/contrib/snap/snapcraft-master.yaml b/contrib/snap/snapcraft-master.yaml index 406cd1c86..a241f1c89 100644 --- a/contrib/snap/snapcraft-master.yaml +++ b/contrib/snap/snapcraft-master.yaml @@ -80,38 +80,22 @@ parts: - -lib - -share - -usr - appstream-glib-dev: + libxmlb-dev: plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false, -Dman=false, -Drpm=false] - source: https://github.com/hughsie/appstream-glib + meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false] + source: https://github.com/hughsie/libxmlb source-type: git build-packages: - python3-pip - - gperf - - intltool - - libarchive-dev - - libgcab-dev - - libgdk-pixbuf2.0-dev - libgirepository1.0-dev - libglib2.0-dev - libgtk-3-dev - libjson-glib-dev - - libsoup2.4-dev - - libsqlite3-dev - - libyaml-dev - - libstemmer-dev - uuid-dev - stage-packages: - - libarchive13 - - libgcab-1.0-0 - - libsoup2.4-1 - - libstemmer0d - - libgdk-pixbuf2.0-0 prime: - -usr/bin - -usr/include - -usr/share/doc - - -usr/lib/*/asb-plugins-5 - -usr/share/bash-completion - -usr/share/aclocal - -usr/lib/*/pkgconfig @@ -310,7 +294,7 @@ parts: - -usr/share/gir-1.0 - -usr/share/upstart - -usr/lib/*/pkgconfig - after: [appstream-glib-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] + after: [libxmlb-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion diff --git a/meson.build b/meson.build index 04b1d4450..ab10bfc13 100644 --- a/meson.build +++ b/meson.build @@ -154,7 +154,7 @@ gudev = dependency('gudev-1.0') if gudev.version().version_compare('>= 232') conf.set('HAVE_GUDEV_232', '1') endif -appstream_glib = dependency('appstream-glib', version : '>= 0.7.4') +libxmlb = dependency('xmlb', version : '>= 0.1.2', fallback : ['libxmlb', 'libxmlb_dep']) gusb = dependency('gusb', version : '>= 0.2.9') sqlite = dependency('sqlite3') libarchive = dependency('libarchive') @@ -305,7 +305,7 @@ configure_file( ) plugin_deps = [] -plugin_deps += appstream_glib +plugin_deps += libxmlb plugin_deps += gio plugin_deps += giounix plugin_deps += gmodule diff --git a/plugins/dell-dock/fu-dell-dock-hub.c b/plugins/dell-dock/fu-dell-dock-hub.c index f0f6d0dd1..aa92b7d19 100644 --- a/plugins/dell-dock/fu-dell-dock-hub.c +++ b/plugins/dell-dock/fu-dell-dock-hub.c @@ -15,8 +15,6 @@ #include "config.h" -#include - #include "fu-usb-device.h" #include "fwupd-error.h" diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index bcacd6b76..461a68b67 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -15,9 +15,9 @@ #include "config.h" -#include #include +#include "fu-common-version.h" #include "fu-usb-device.h" #include "fwupd-error.h" @@ -369,7 +369,7 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, } /* minimum EC version this code will support */ - if (as_utils_vercmp (self->ec_version, self->ec_minimum_version) < 0) { + if (fu_common_vercmp (self->ec_version, self->ec_minimum_version) < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "dock containing EC version %s is not supported", self->ec_version); @@ -533,7 +533,7 @@ fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) } /* TODO: Drop when bumping minimum EC version to 13+ */ - if (as_utils_vercmp (self->ec_version, "00.00.00.13") < 0) + if (fu_common_vercmp (self->ec_version, "00.00.00.13") < 0) g_print ("\nEC Reboot API may fail on EC %s. Please manually power cycle dock.\n", self->ec_version); g_debug ("Rebooting %s", fu_device_get_name (device)); @@ -618,7 +618,7 @@ fu_dell_dock_ec_commit_package (FuDevice *device, GBytes *blob_fw, g_debug ("\tpkg_version: %x", self->raw_versions->pkg_version); /* TODO: Drop when updating minimum EC to 11+ */ - if (as_utils_vercmp (self->ec_version, "00.00.00.11") < 0) { + if (fu_common_vercmp (self->ec_version, "00.00.00.11") < 0) { g_debug ("EC %s doesn't support package version, ignoring", self->ec_version); return TRUE; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index 4811a1c64..5897b16b1 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -16,7 +16,6 @@ #include "config.h" -#include #include #include "fu-common.h" diff --git a/plugins/dell-dock/fu-dell-dock-status.c b/plugins/dell-dock/fu-dell-dock-status.c index 478ed0a08..ff820236e 100644 --- a/plugins/dell-dock/fu-dell-dock-status.c +++ b/plugins/dell-dock/fu-dell-dock-status.c @@ -16,7 +16,6 @@ #include "config.h" #include -#include #include "fu-dell-dock-common.h" diff --git a/plugins/dfu/meson.build b/plugins/dfu/meson.build index 9fdc95bf7..cac1a82b1 100644 --- a/plugins/dfu/meson.build +++ b/plugins/dfu/meson.build @@ -26,7 +26,6 @@ dfu = static_library( 'dfu-target-avr.c', ], dependencies : [ - appstream_glib, giounix, libm, gusb, @@ -72,7 +71,7 @@ dfu_tool = executable( include_directories('../../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, libm, gusb, @@ -123,7 +122,7 @@ if get_option('tests') include_directories('../../src'), ], dependencies : [ - appstream_glib, + libxmlb, gio, gusb, gudev, diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index 140418a8a..098af7991 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -48,7 +48,7 @@ executable( include_directories('../../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, gusb, gudev, diff --git a/plugins/wacomhid/meson.build b/plugins/wacomhid/meson.build index 5cdf65cce..cd655bffa 100644 --- a/plugins/wacomhid/meson.build +++ b/plugins/wacomhid/meson.build @@ -49,7 +49,7 @@ if get_option('tests') include_directories('../../src'), ], dependencies : [ - appstream_glib, + libxmlb, gio, gusb, gudev, diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 4537a1167..5e4a295b0 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -77,37 +77,21 @@ parts: - -lib - -share - -usr - appstream-glib-dev: + libxmlb-dev: plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false, -Dman=false, -Drpm=false] - source: https://github.com/hughsie/appstream-glib/archive/appstream_glib_0_7_9.tar.gz + meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false] + source: https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.2.tar.xz build-packages: - python3-pip - - gperf - - intltool - - libarchive-dev - - libgcab-dev - - libgdk-pixbuf2.0-dev - libgirepository1.0-dev - libglib2.0-dev - libgtk-3-dev - libjson-glib-dev - - libsoup2.4-dev - - libsqlite3-dev - - libyaml-dev - - libstemmer-dev - uuid-dev - stage-packages: - - libarchive13 - - libgcab-1.0-0 - - libsoup2.4-1 - - libstemmer0d - - libgdk-pixbuf2.0-0 prime: - -usr/bin - -usr/include - -usr/share/doc - - -usr/lib/*/asb-plugins-5 - -usr/share/bash-completion - -usr/share/aclocal - -usr/lib/*/pkgconfig @@ -305,7 +289,7 @@ parts: - -usr/share/gir-1.0 - -usr/share/upstart - -usr/lib/*/pkgconfig - after: [appstream-glib-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] + after: [libxmlb-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion diff --git a/src/fu-common-cab.c b/src/fu-common-cab.c index 49fdf0a56..f816f0b03 100644 --- a/src/fu-common-cab.c +++ b/src/fu-common-cab.c @@ -15,7 +15,9 @@ #include "fwupd-error.h" -#ifdef HAVE_GCAB_1_0 +#ifndef HAVE_GCAB_1_0 +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCabCabinet, g_object_unref) +#endif static GCabFile * _gcab_cabinet_get_file_by_name (GCabCabinet *cabinet, const gchar *basename) @@ -23,50 +25,83 @@ _gcab_cabinet_get_file_by_name (GCabCabinet *cabinet, const gchar *basename) GPtrArray *folders = gcab_cabinet_get_folders (cabinet); for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); +#ifdef HAVE_GCAB_1_0 GCabFile *cabfile = gcab_folder_get_file_by_name (cabfolder, basename); if (cabfile != NULL) return cabfile; +#else + g_autoptr(GSList) files = gcab_folder_get_files (cabfolder); + for (GSList *l = files; l != NULL; l = l->next) { + GCabFile *cabfile = GCAB_FILE (l->data); + if (g_strcmp0 (gcab_file_get_name (cabfile), basename) == 0) + return cabfile; + } +#endif } return NULL; } -/* sets the firmware and signature blobs on AsRelease */ -static gboolean -fu_common_store_from_cab_release (AsRelease *release, GCabCabinet *cabinet, GError **error) +#ifndef HAVE_GCAB_1_0 +static GBytes * +_gcab_file_get_bytes (GCabFile *cabfile) +{ + GBytes *blob = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(GError) error_local = NULL; + + fn = g_build_filename (g_object_get_data (G_OBJECT (cabfile), + "fwupd::DecompressPath"), + gcab_file_get_extract_name (cabfile), + NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to read temp file: %s", error_local->message); + return NULL; + } + return blob; +} +#endif + +/* sets the firmware and signature blobs on XbNode */ +static gboolean +fu_common_store_from_cab_release (XbNode *release, GCabCabinet *cabinet, GError **error) { - AsChecksum *csum_tmp; GCabFile *cabfile; GBytes *blob; - guint64 size; - g_autofree gchar *basename = NULL; - g_autofree gchar *checksum = NULL; + const gchar *csum_filename; const gchar *suffixes[] = { "asc", "p7b", "p7c", NULL }; + g_autofree gchar *basename = NULL; + g_autofree gchar *release_key = NULL; + g_autoptr(XbNode) csum_tmp = NULL; + g_autoptr(XbNode) nsize = NULL; /* ensure we always have a content checksum */ - csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum_tmp == NULL) { - g_autoptr(AsChecksum) csum = as_checksum_new (); - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); + csum_tmp = xb_node_query_first (release, "checksum[@target='content']", NULL); + if (csum_tmp != NULL) { + csum_filename = xb_node_get_attr (csum_tmp, "filename"); + } else { /* if this isn't true, a firmware needs to set in * the metainfo.xml file something like: * */ - as_checksum_set_filename (csum, "firmware.bin"); - as_release_add_checksum (release, csum); - csum_tmp = csum; + csum_filename = "firmware.bin"; } /* get the main firmware file */ - basename = g_path_get_basename (as_checksum_get_filename (csum_tmp)); + basename = g_path_get_basename (csum_filename); cabfile = _gcab_cabinet_get_file_by_name (cabinet, basename); if (cabfile == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "cannot find %s in archive", - as_checksum_get_filename (csum_tmp)); + basename); return FALSE; } +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -76,35 +111,41 @@ fu_common_store_from_cab_release (AsRelease *release, GCabCabinet *cabinet, GErr } /* set the blob */ - as_release_set_blob (release, basename, blob); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", basename); + xb_node_set_data (release, release_key, blob); - /* set if unspecified, but error out if specified and incorrect */ - size = as_release_get_size (release, AS_SIZE_KIND_INSTALLED); - if (size == 0) { - as_release_set_size (release, AS_SIZE_KIND_INSTALLED, - g_bytes_get_size (blob)); - } else if (size != g_bytes_get_size (blob)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "contents size invalid, expected " - "%" G_GSIZE_FORMAT ", got %" G_GUINT64_FORMAT, - g_bytes_get_size (blob), size); - return FALSE; + /* set as metadata if unset, but error if specified and incorrect */ + nsize = xb_node_query_first (release, "size[@type='installed']", NULL); + if (nsize != NULL) { + guint64 size = fu_common_strtoull (xb_node_get_text (nsize)); + if (size != g_bytes_get_size (blob)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "contents size invalid, expected " + "%" G_GSIZE_FORMAT ", got %" G_GUINT64_FORMAT, + g_bytes_get_size (blob), size); + return FALSE; + } + } else { + guint64 size = g_bytes_get_size (blob); + g_autoptr(GBytes) blob_sz = g_bytes_new (&size, sizeof(guint64)); + xb_node_set_data (release, "fwupd::ReleaseSize", blob_sz); } /* set if unspecified, but error out if specified and incorrect */ - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); - if (as_checksum_get_value (csum_tmp) == NULL) { - as_checksum_set_value (csum_tmp, checksum); - } else if (g_strcmp0 (checksum, as_checksum_get_value (csum_tmp)) != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "contents checksum invalid, expected %s, got %s", - checksum, - as_checksum_get_value (csum_tmp)); - return FALSE; + if (csum_tmp != NULL && xb_node_get_text (csum_tmp) != NULL) { + g_autofree gchar *checksum = NULL; + checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + if (g_strcmp0 (checksum, xb_node_get_text (csum_tmp)) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "contents checksum invalid, expected %s, got %s", + checksum, + xb_node_get_text (csum_tmp)); + return FALSE; + } } /* if the signing file exists, set that too */ @@ -113,7 +154,12 @@ fu_common_store_from_cab_release (AsRelease *release, GCabCabinet *cabinet, GErr basename_sig = g_strdup_printf ("%s.%s", basename, suffixes[i]); cabfile = _gcab_cabinet_get_file_by_name (cabinet, basename_sig); if (cabfile != NULL) { + g_autofree gchar *release_key_sig = NULL; +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error (error, FWUPD_ERROR, @@ -122,7 +168,9 @@ fu_common_store_from_cab_release (AsRelease *release, GCabCabinet *cabinet, GErr basename_sig); return FALSE; } - as_release_set_blob (release, basename_sig, blob); + release_key_sig = g_strdup_printf ("fwupd::ReleaseBlob(%s)", + basename_sig); + xb_node_set_data (release, release_key_sig, blob); } } @@ -130,22 +178,21 @@ fu_common_store_from_cab_release (AsRelease *release, GCabCabinet *cabinet, GErr return TRUE; } -/* adds each GCabFile to the store */ +/* adds each GCabFile to the silo */ static gboolean -fu_common_store_from_cab_file (AsStore *store, GCabCabinet *cabinet, +fu_common_store_from_cab_file (XbBuilder *builder, GCabCabinet *cabinet, GCabFile *cabfile, GError **error) { GBytes *blob; - GPtrArray *releases; - g_autoptr(AsApp) app = NULL; g_autoptr(GError) error_local = NULL; -#if !AS_CHECK_VERSION(0,7,5) - g_autofree gchar *cache_fn = NULL; - g_autofree gchar *cachedir = NULL; -#endif + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); /* parse file */ +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -153,9 +200,10 @@ fu_common_store_from_cab_file (AsStore *store, GCabCabinet *cabinet, "no GBytes from GCabFile"); return FALSE; } - app = as_app_new (); -#if AS_CHECK_VERSION(0,7,5) - if (!as_app_parse_data (app, blob, AS_APP_PARSE_FLAG_NONE, &error_local)) { + if (!xb_builder_source_load_xml (source, + g_bytes_get_data (blob, NULL), + XB_BUILDER_SOURCE_FLAG_NONE, + &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -163,54 +211,15 @@ fu_common_store_from_cab_file (AsStore *store, GCabCabinet *cabinet, error_local->message); return FALSE; } -#else - cachedir = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); - cache_fn = g_build_filename (cachedir, gcab_file_get_extract_name (cabfile), NULL); - if (!fu_common_mkdir_parent (cache_fn, error)) - return FALSE; - if (!g_file_set_contents (cache_fn, g_bytes_get_data (blob, NULL), - g_bytes_get_size (blob), &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "could not save temporary MetaInfo XML to %s: %s", - cache_fn, error_local->message); - return FALSE; - } - if (!as_app_parse_file (app, cache_fn, AS_APP_PARSE_FLAG_NONE, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "could not parse MetaInfo XML: %s", - error_local->message); - return FALSE; - } -#endif - - /* process each listed release */ - releases = as_app_get_releases (app); - if (releases->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no releases in metainfo file"); - return FALSE; - } - for (guint i = 0; i < releases->len; i++) { - AsRelease *release = g_ptr_array_index (releases, i); - g_debug ("processing release: %s", as_release_get_version (release)); - if (!fu_common_store_from_cab_release (release, cabinet, error)) - return FALSE; - } + xb_builder_import_source (builder, source); /* success */ - as_store_add_app (store, app); return TRUE; } -/* adds each GCabFolder to the store */ +/* adds each GCabFolder to the silo */ static gboolean -fu_common_store_from_cab_folder (AsStore *store, GCabCabinet *cabinet, +fu_common_store_from_cab_folder (XbBuilder *builder, GCabCabinet *cabinet, GCabFolder *cabfolder, GError **error) { g_autoptr(GSList) cabfiles = gcab_folder_get_files (cabfolder); @@ -218,8 +227,8 @@ fu_common_store_from_cab_folder (AsStore *store, GCabCabinet *cabinet, GCabFile *cabfile = GCAB_FILE (l->data); const gchar *fn = gcab_file_get_extract_name (cabfile); g_debug ("processing file: %s", fn); - if (as_format_guess_kind (fn) == AS_FORMAT_KIND_METAINFO) { - if (!fu_common_store_from_cab_file (store, cabinet, cabfile, error)) { + if (g_str_has_suffix (fn, ".metainfo.xml")) { + if (!fu_common_store_from_cab_file (builder, cabinet, cabfile, error)) { g_prefix_error (error, "%s could not be loaded: ", gcab_file_get_extract_name (cabfile)); return FALSE; @@ -232,11 +241,12 @@ fu_common_store_from_cab_folder (AsStore *store, GCabCabinet *cabinet, typedef struct { guint64 size_total; guint64 size_max; + const gchar *decompress_path; GError *error; } FuCommonCabHelper; static gboolean -as_cab_store_file_cb (GCabFile *file, gpointer user_data) +fu_common_store_file_cb (GCabFile *file, gpointer user_data) { FuCommonCabHelper *helper = (FuCommonCabHelper *) user_data; g_autofree gchar *basename = NULL; @@ -279,34 +289,54 @@ as_cab_store_file_cb (GCabFile *file, gpointer user_data) /* ignore the dirname completely */ basename = g_path_get_basename (name); gcab_file_set_extract_name (file, basename); + +#ifndef HAVE_GCAB_1_0 + /* set this for old versions of GCab */ + g_object_set_data_full (G_OBJECT (file), + "fwupd::DecompressPath", + g_strdup (helper->decompress_path), + g_free); +#endif + return TRUE; } /** - * fu_common_store_from_cab_bytes: + * fu_common_cab_build_silo: * @blob: A readable blob * @size_max: The maximum size of the archive * @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN * - * Create an AppStream store from a cabinet archive. + * Create an AppStream silo from a cabinet archive. * - * Returns: a store, or %NULL on error + * Returns: a #XbSilo, or %NULL on error **/ -AsStore * -fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) +XbSilo * +fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) { - FuCommonCabHelper helper = { 0 }; + FuCommonCabHelper helper = { + .size_total = 0, + .size_max = size_max, + .error = NULL, + }; GPtrArray *folders; - g_autoptr(AsStore) store = as_store_new (); +#ifndef HAVE_GCAB_1_0 + g_autofree gchar *tmp_path = NULL; + g_autoptr(GFile) tmp_file = NULL; +#endif + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) ip = NULL; + g_autoptr(GPtrArray) components = NULL; /* load from a seekable stream */ ip = g_memory_input_stream_new_from_bytes (blob); if (!gcab_cabinet_load (cabinet, ip, NULL, error)) return NULL; +#ifdef HAVE_GCAB_1_0 /* check the size is sane */ if (gcab_cabinet_get_size (cabinet) > size_max) { g_autofree gchar *sz_val = g_format_size (gcab_cabinet_get_size (cabinet)); @@ -320,9 +350,8 @@ fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) } /* decompress the file to memory */ - helper.size_max = size_max; if (!gcab_cabinet_extract_simple (cabinet, NULL, - as_cab_store_file_cb, &helper, + fu_common_store_file_cb, &helper, NULL, &error_local)) { g_set_error_literal (error, FWUPD_ERROR, @@ -330,6 +359,29 @@ fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) error_local->message); return NULL; } +#else + /* decompress to /tmp */ + tmp_path = g_dir_make_tmp ("fwupd-XXXXXX", &error_local); + if (tmp_path == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to create temp dir: %s", + error_local->message); + return FALSE; + } + helper.decompress_path = tmp_path; + tmp_file = g_file_new_for_path (tmp_path); + if (!gcab_cabinet_extract_simple (cabinet, tmp_file, + fu_common_store_file_cb, &helper, + NULL, &error_local)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + error_local->message); + return NULL; + } +#endif /* the file callback set an error */ if (helper.error != NULL) { @@ -337,53 +389,59 @@ fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) return NULL; } + /* verbose profiling */ + if (g_getenv ("FWUPD_VERBOSE") != NULL) { + xb_builder_set_profile_flags (builder, + XB_SILO_PROFILE_FLAG_XPATH | + XB_SILO_PROFILE_FLAG_DEBUG); + } + /* look at each folder */ folders = gcab_cabinet_get_folders (cabinet); for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); g_debug ("processing folder: %u/%u", i + 1, folders->len); - if (!fu_common_store_from_cab_folder (store, cabinet, cabfolder, error)) + if (!fu_common_store_from_cab_folder (builder, cabinet, cabfolder, error)) return NULL; } - /* did we get any valid AsApps */ - if (as_store_get_size (store) == 0) { - g_set_error_literal (error, + /* did we get any valid files */ + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return NULL; + + /* this looks weird, but metainfo files have no node */ + components = xb_silo_query (silo, "component", 0, &error_local); + if (components == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "archive contained no valid metadata: %s", + error_local->message); + return NULL; + } + + /* process each listed release */ + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); + g_autoptr(GPtrArray) releases = NULL; + releases = xb_node_query (component, "releases/release", 0, &error_local); + if (releases == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "archive contained no valid metadata"); - return NULL; + "no releases in metainfo file: %s", + error_local->message); + return NULL; + } + for (guint j = 0; j < releases->len; j++) { + XbNode *rel = g_ptr_array_index (releases, j); + g_debug ("processing release: %s", xb_node_get_attr (rel, "version")); + if (!fu_common_store_from_cab_release (rel, cabinet, error)) + return NULL; + } } /* success */ - return g_steal_pointer (&store); + return g_steal_pointer (&silo); } - -#else - -AsStore * -fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) -{ - g_autoptr(AsStore) store = as_store_new (); - g_autoptr(GError) error_local = NULL; - - /* this is klunky as we have to write actual files to /tmp */ - if (!as_store_from_bytes (store, blob, NULL, &error_local)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - error_local->message); - return NULL; - } - - /* did we get any valid AsApps */ - if (as_store_get_size (store) == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "archive contained no valid metadata"); - return NULL; - } - return g_steal_pointer (&store); -} -#endif diff --git a/src/fu-common-cab.h b/src/fu-common-cab.h index 28cf456f8..2f1da8d9f 100644 --- a/src/fu-common-cab.h +++ b/src/fu-common-cab.h @@ -7,9 +7,9 @@ #ifndef __FU_COMMON_CAB_H #define __FU_COMMON_CAB_H -#include +#include -AsStore *fu_common_store_from_cab_bytes (GBytes *blob, +XbSilo *fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error); diff --git a/src/fu-config.c b/src/fu-config.c index 2d22a56a6..471bf709c 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -8,7 +8,7 @@ #include "config.h" -#include +#include #include #include #include @@ -31,7 +31,7 @@ struct _FuConfig GPtrArray *blacklist_devices; GPtrArray *blacklist_plugins; guint64 archive_size_max; - AsStore *store_remotes; + XbSilo *silo; GHashTable *os_release; }; @@ -132,70 +132,26 @@ fu_config_get_remote_agreement_default (FwupdRemote *self, GError **error) } static GString * -fu_config_get_remote_agreement_for_app (FwupdRemote *self, AsApp *app, GError **error) +fu_config_get_remote_agreement_for_app (FwupdRemote *self, XbNode *component, GError **error) { -#if AS_CHECK_VERSION(0,7,8) - const gchar *tmp = NULL; - AsAgreement *agreement; - AsAgreementSection *section; - - /* get the default agreement section */ - agreement = as_app_get_agreement_default (app); - if (agreement == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No agreement found"); - return NULL; - } - section = as_agreement_get_section_default (agreement); - if (section == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No default section for agreement found"); - return NULL; - } - tmp = as_agreement_section_get_description (section, NULL); - if (tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No description found in agreement section"); - return NULL; - } - return g_string_new (tmp); -#else - AsFormat *format; - GNode *n; - g_autoptr(AsNode) root = NULL; - g_autoptr(GFile) file = NULL; - - /* parse the XML file */ - format = as_app_get_format_default (app); - if (format == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No format for Metainfo file"); - return NULL; - } - file = g_file_new_for_path (as_format_get_filename (format)); - root = as_node_from_file (file, AS_NODE_FROM_XML_FLAG_NONE, NULL, error); - if (root == NULL) - return NULL; + XbNode *n; + g_autofree gchar *tmp = NULL; + g_autoptr(GError) error_local = NULL; /* manually find the first agreement section */ - n = as_node_find (root, "component/agreement/agreement_section/description"); + n = xb_node_query_first (component, "agreement/agreement_section/description", &error_local); if (n == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No agreement description found"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No agreement description found: %s", + error_local->message); return NULL; } - return as_node_to_xml (n->children, AS_NODE_TO_XML_FLAG_INCLUDE_SIBLINGS); -#endif + tmp = xb_node_export (n, XB_NODE_EXPORT_FLAG_NONE, error); + if (tmp == NULL) + return NULL; + return g_string_new (tmp); } static gchar * @@ -248,9 +204,13 @@ fu_config_add_remotes_for_path (FuConfig *self, const gchar *path, GError **erro if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DOWNLOAD) { g_autoptr(GString) agreement_markup = NULL; g_autofree gchar *component_id = fu_config_build_remote_component_id (remote); - AsApp *app = as_store_get_app_by_id (self->store_remotes, component_id); - if (app != NULL) { - agreement_markup = fu_config_get_remote_agreement_for_app (remote, app, error); + g_autoptr(XbNode) component = NULL; + g_autofree gchar *xpath = NULL; + + xpath = g_strdup_printf ("components/component/id[text()='%s']/..", component_id); + component = xb_silo_query_first (self->silo, xpath, NULL); + if (component != NULL) { + agreement_markup = fu_config_get_remote_agreement_for_app (remote, component, error); } else { agreement_markup = fu_config_get_remote_agreement_default (remote, error); } @@ -453,13 +413,48 @@ fu_config_load_from_file (FuConfig *self, const gchar *config_file, return TRUE; } +static gboolean +fu_config_load_metainfos (XbBuilder *builder, GError **error) +{ + const gchar *fn; + g_autofree gchar *datadir = NULL; + g_autofree gchar *metainfo_path = NULL; + g_autoptr(GDir) dir = NULL; + + /* pkg metainfo dir */ + datadir = fu_common_get_path (FU_PATH_KIND_DATADIR_PKG); + metainfo_path = g_build_filename (datadir, "metainfo", NULL); + if (!g_file_test (metainfo_path, G_FILE_TEST_EXISTS)) + return TRUE; + + g_debug ("loading %s", metainfo_path); + dir = g_dir_open (metainfo_path, 0, error); + if (dir == NULL) + return FALSE; + while ((fn = g_dir_read_name (dir)) != NULL) { + if (g_str_has_suffix (fn, ".metainfo.xml")) { + g_autofree gchar *filename = g_build_filename (metainfo_path, fn, NULL); + g_autoptr(GFile) file = g_file_new_for_path (filename); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, error)) + return FALSE; + xb_builder_import_source (builder, source); + } + } + return TRUE; +} + gboolean fu_config_load (FuConfig *self, GError **error) { - g_autofree gchar *datadir = NULL; g_autofree gchar *configdir = NULL; - g_autofree gchar *metainfo_path = NULL; g_autofree gchar *config_file = NULL; + g_autofree gchar *cachedirpkg = NULL; + g_autofree gchar *xmlbfn = NULL; + g_autoptr(GFile) xmlb = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); @@ -477,16 +472,18 @@ fu_config_load (FuConfig *self, GError **error) self->os_release = fwupd_get_os_release (error); if (self->os_release == NULL) return FALSE; - as_store_add_filter (self->store_remotes, AS_APP_KIND_SOURCE); - datadir = fu_common_get_path (FU_PATH_KIND_DATADIR_PKG); - metainfo_path = g_build_filename (datadir, "metainfo", NULL); - if (g_file_test (metainfo_path, G_FILE_TEST_EXISTS)) { - if (!as_store_load_path (self->store_remotes, - metainfo_path, - NULL, /* cancellable */ - error)) - return FALSE; - } + if (!fu_config_load_metainfos (builder, error)) + return FALSE; + + /* build the metainfo silo */ + cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); + xmlbfn = g_build_filename (cachedirpkg, "metainfo.xmlb", NULL); + xmlb = g_file_new_for_path (xmlbfn); + self->silo = xb_builder_ensure (builder, xmlb, + XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID, + NULL, error); + if (self->silo == NULL) + return FALSE; /* load remotes */ if (!fu_config_load_remotes (self, error)) @@ -547,7 +544,6 @@ fu_config_init (FuConfig *self) self->blacklist_plugins = g_ptr_array_new_with_free_func (g_free); self->remotes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); self->monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - self->store_remotes = as_store_new (); } static void @@ -557,12 +553,13 @@ fu_config_finalize (GObject *obj) if (self->os_release != NULL) g_hash_table_unref (self->os_release); + if (self->silo != NULL) + g_object_unref (self->silo); g_key_file_unref (self->keyfile); g_ptr_array_unref (self->blacklist_devices); g_ptr_array_unref (self->blacklist_plugins); g_ptr_array_unref (self->remotes); g_ptr_array_unref (self->monitors); - g_object_unref (self->store_remotes); G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj); } diff --git a/src/fu-engine.c b/src/fu-engine.c index 7bfa668ed..04aa648e2 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -56,7 +56,7 @@ struct _FuEngine FwupdStatus status; guint percentage; FuHistory *history; - AsStore *store; + XbSilo *silo; gboolean coldplug_running; guint coldplug_id; guint coldplug_delay; @@ -200,53 +200,114 @@ fu_engine_device_changed_cb (FuDeviceList *device_list, FuDevice *device, FuEngi fu_engine_emit_device_changed (self, device); } -static const gchar * -_as_release_get_metadata_item (AsRelease *release, const gchar *key) +/* convert hex and decimal versions to dotted style */ +static gchar * +fu_engine_get_release_version (FuEngine *self, XbNode *component, XbNode *rel) { - GBytes *blob = as_release_get_blob (release, key); - if (blob == NULL) + FuVersionFormat fmt = FU_VERSION_FORMAT_TRIPLET; + const gchar *quirk; + const gchar *version; + const gchar *version_format; + guint64 ver_uint32; + + /* get version */ + version = xb_node_get_attr (rel, "version"); + if (version == NULL) return NULL; - return (const gchar *) g_bytes_get_data (blob, NULL); + + /* already dotted notation */ + if (g_strstr_len (version, -1, ".") != NULL) + return g_strdup (version); + + /* fall back to the quirk database until all files have metadata */ + quirk = fu_quirks_lookup_by_id (self->quirks, + "DaemonVersionFormat=quad", + FU_QUIRKS_DAEMON_VERSION_FORMAT); + if (quirk != NULL) { + const gchar *id = xb_node_query_text (component, "id", NULL); + g_auto(GStrv) globs = g_strsplit (quirk, ",", -1); + for (guint i = 0; globs[i] != NULL; i++) { + if (fnmatch (globs[i], id, 0) == 0) { + fmt = FU_VERSION_FORMAT_QUAD; + break; + } + } + } + + /* specified in metadata */ + version_format = xb_node_query_text (component, + "custom/value[@key='LVFS::VersionFormat']", + NULL); + if (version_format != NULL) + fmt = fu_common_version_format_from_string (version_format); + + /* don't touch my version! */ + if (fmt == FU_VERSION_FORMAT_PLAIN) + return g_strdup (version); + + /* parse as integer */ + ver_uint32 = fu_common_strtoull (version); + if (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 void fu_engine_set_release_from_appstream (FuEngine *self, FwupdRelease *rel, - AsApp *app, - AsRelease *release) + XbNode *component, + XbNode *release) { - AsChecksum *csum; FwupdRemote *remote = NULL; const gchar *tmp; const gchar *remote_id; + guint64 tmp64; + g_autofree gchar *version_rel = NULL; + g_autoptr(XbNode) description = NULL; - /* set from the AsApp */ - fwupd_release_set_appstream_id (rel, as_app_get_id (app)); - fwupd_release_set_homepage (rel, as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE)); - fwupd_release_set_license (rel, as_app_get_project_license (app)); - fwupd_release_set_name (rel, as_app_get_name (app, NULL)); - fwupd_release_set_summary (rel, as_app_get_comment (app, NULL)); - fwupd_release_set_vendor (rel, as_app_get_developer_name (app, NULL)); - fwupd_release_set_appstream_id (rel, as_app_get_id (app)); + /* 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); + tmp = xb_node_query_text (component, "name", NULL); + if (tmp != NULL) + fwupd_release_set_name (rel, tmp); + tmp = xb_node_query_text (component, "summary", NULL); + if (tmp != NULL) + fwupd_release_set_summary (rel, tmp); + tmp = xb_node_query_text (component, "developer_name", NULL); + if (tmp != NULL) + fwupd_release_set_vendor (rel, tmp); + + /* the version is fixed up at runtime */ + version_rel = fu_engine_get_release_version (self, component, release); + if (version_rel != NULL) + fwupd_release_set_version (rel, version_rel); /* find the remote */ - remote_id = _as_release_get_metadata_item (release, "fwupd::RemoteId"); + remote_id = xb_node_query_text (component, "../custom/fwupd::RemoteId", NULL); if (remote_id != NULL) { fwupd_release_set_remote_id (rel, remote_id); remote = fu_config_get_remote_by_id (self->config, remote_id); - if (remote == NULL) { - g_warning ("no remote found for release %s", - as_release_get_version (release)); - } + if (remote == NULL) + g_warning ("no remote found for release %s", version_rel); } - - tmp = as_release_get_version (release); - if (tmp != NULL) - fwupd_release_set_version (rel, tmp); - tmp = as_release_get_description (release, NULL); - if (tmp != NULL) - fwupd_release_set_description (rel, tmp); - tmp = as_release_get_location_default (release); + description = xb_node_query_first (release, "description", NULL); + if (description != NULL) { + g_autofree gchar *xml = NULL; + xml = xb_node_export (description, XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, NULL); + if (xml != NULL) + fwupd_release_set_description (rel, xml); + } + tmp = xb_node_query_text (release, "location", NULL); if (tmp != NULL) { g_autofree gchar *uri = NULL; if (remote != NULL) @@ -255,42 +316,39 @@ fu_engine_set_release_from_appstream (FuEngine *self, uri = g_strdup (tmp); fwupd_release_set_uri (rel, uri); } - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum != NULL) { - tmp = as_checksum_get_filename (csum); - if (tmp != NULL) - fwupd_release_set_filename (rel, tmp); + 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, "checksum[@target='container']", NULL); + if (tmp != NULL) + fwupd_release_add_checksum (rel, tmp); + tmp64 = xb_node_query_text_as_uint (release, "size[@type='installed']", NULL); + if (tmp64 != G_MAXUINT64) { + fwupd_release_set_size (rel, tmp64); + } else { + 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); + } } - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTAINER); - if (csum != NULL) { - tmp = as_checksum_get_value (csum); - if (tmp != NULL) - fwupd_release_add_checksum (rel, tmp); - } - fwupd_release_set_size (rel, as_release_get_size (release, AS_SIZE_KIND_INSTALLED)); } -/* finds the remote-id for the first firmware in the store that matches this +/* finds the remote-id for the first firmware in the silo that matches this * container checksum */ static const gchar * fu_engine_get_remote_id_for_checksum (FuEngine *self, const gchar *csum) { - GPtrArray *array = as_store_get_apps (self->store); - for (guint i = 0; i < array->len; i++) { - AsApp *app = g_ptr_array_index (array, i); - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - AsChecksum *checksum; - checksum = as_release_get_checksum_by_target (release, - AS_CHECKSUM_TARGET_CONTAINER); - if (checksum == NULL) - continue; - if (g_strcmp0 (csum, as_checksum_get_value (checksum)) == 0) - return _as_release_get_metadata_item (release, "fwupd::RemoteId"); - } - } - return NULL; + g_autofree gchar *xpath = NULL; + g_autoptr(XbNode) key = NULL; + xpath = g_build_filename ("components", "component", "releases", "release", + "checksum[@target='container']", "..", "..", + "..", "..", "custom", "fwupd::RemoteId", NULL); + + key = xb_silo_query_first (self->silo, xpath, NULL); + if (key == NULL) + return NULL; + return xb_node_get_text (key); } /** @@ -335,63 +393,6 @@ fu_engine_unlock (FuEngine *self, const gchar *device_id, GError **error) return TRUE; } -static AsApp * -fu_engine_verify_update_device_to_app (FuDevice *device) -{ - AsApp *app = NULL; - GPtrArray *checksums; - g_autofree gchar *id = NULL; - g_autoptr(AsFormat) format = NULL; - g_autoptr(AsProvide) prov = NULL; - g_autoptr(AsRelease) rel = NULL; - - /* make a plausible ID */ - id = g_strdup_printf ("%s.firmware", fu_device_get_guid_default (device)); - - /* add app to store */ - app = as_app_new (); - as_app_set_id (app, id); - as_app_set_kind (app, AS_APP_KIND_FIRMWARE); - rel = as_release_new (); - as_release_set_version (rel, fu_device_get_version (device)); - checksums = fu_device_get_checksums (device); - for (guint j = 0; j < checksums->len; j++) { - const gchar *checksum = g_ptr_array_index (checksums, j); - g_autoptr(AsChecksum) csum = as_checksum_new (); - as_checksum_set_kind (csum, fwupd_checksum_guess_kind (checksum)); - as_checksum_set_value (csum, checksum); - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - as_release_add_checksum (rel, csum); - } - as_app_add_release (app, rel); - prov = as_provide_new (); - as_provide_set_kind (prov, AS_PROVIDE_KIND_FIRMWARE_FLASHED); - as_provide_set_value (prov, fu_device_get_guid_default (device)); - as_app_add_provide (app, prov); - format = as_format_new (); - as_format_set_kind (format, AS_FORMAT_KIND_UNKNOWN); - as_app_add_format (app, format); - return app; -} - -static AsStore * -fu_engine_load_verify_store (GError **error) -{ - const gchar *fn = "/var/lib/fwupd/verify.xml"; - g_autoptr(AsStore) store = NULL; - g_autoptr(GFile) file = NULL; - - /* load existing store */ - store = as_store_new (); - as_store_set_api_version (store, 0.9); - file = g_file_new_for_path (fn); - if (g_file_query_exists (file, NULL)) { - if (!as_store_from_file (store, file, NULL, NULL, error)) - return NULL; - } - return g_steal_pointer (&store); -} - /** * fu_engine_modify_remote: * @self: A #FuEngine @@ -400,7 +401,7 @@ fu_engine_load_verify_store (GError **error) * @value: the key, e.g. `true` * @error: A #GError, or %NULL * - * Updates the verification store entry for a specific device. + * Updates the verification silo entry for a specific device. * * Returns: %TRUE for success **/ @@ -507,13 +508,25 @@ fu_engine_modify_device (FuEngine *self, return FALSE; } +static const gchar * +fu_engine_checksum_type_to_string (GChecksumType checksum_type) +{ + if (checksum_type == G_CHECKSUM_SHA1) + return "sha1"; + if (checksum_type == G_CHECKSUM_SHA256) + return "sha256"; + if (checksum_type == G_CHECKSUM_SHA512) + return "sha512"; + return "sha1"; +} + /** * fu_engine_verify_update: * @self: A #FuEngine * @device_id: A device ID * @error: A #GError, or %NULL * - * Updates the verification store entry for a specific device. + * Updates the verification silo entry for a specific device. * * Returns: %TRUE for success **/ @@ -522,11 +535,17 @@ fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error) { FuPlugin *plugin; GPtrArray *checksums; - const gchar *fn = "/var/lib/fwupd/verify.xml"; - g_autoptr(AsApp) app = NULL; - g_autoptr(AsStore) store = NULL; + GPtrArray *guids; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; g_autoptr(FuDevice) device = NULL; g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderNode) component = NULL; + g_autoptr(XbBuilderNode) provides = NULL; + g_autoptr(XbBuilderNode) release = NULL; + g_autoptr(XbBuilderNode) releases = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -563,37 +582,67 @@ fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error) return FALSE; } - /* load existing store */ - store = fu_engine_load_verify_store (error); - if (store == NULL) + /* build XML */ + component = xb_builder_node_insert (NULL, "component", + "type", "firmware", + NULL); + provides = xb_builder_node_insert (component, "provides", NULL); + guids = fu_device_get_guids (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autoptr(XbBuilderNode) provide = NULL; + provide = xb_builder_node_insert (provides, "firmware", + "type", "flashed", + NULL); + xb_builder_node_set_text (provide, guid, -1); + } + releases = xb_builder_node_insert (component, "releases", NULL); + release = xb_builder_node_insert (releases, "release", + "version", fu_device_get_version (device), + NULL); + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + GChecksumType kind = fwupd_checksum_guess_kind (checksum); + g_autoptr(XbBuilderNode) csum = NULL; + csum = xb_builder_node_insert (provides, "checksum", + "type", fu_engine_checksum_type_to_string (kind), + "target", "content", + NULL); + xb_builder_node_set_text (csum, checksum, -1); + } + xb_builder_import_node (builder, component); + + /* save silo */ + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id); + file = g_file_new_for_path (fn); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + if (!xb_silo_export_file (silo, file, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE, + NULL, error)) return FALSE; - /* add to store */ - app = fu_engine_verify_update_device_to_app (device); - as_store_remove_app_by_id (store, as_app_get_id (app)); - as_store_add_app (store, app); - - /* write */ - g_debug ("writing %s", fn); - file = g_file_new_for_path (fn); - return as_store_to_file (store, file, - AS_NODE_TO_XML_FLAG_ADD_HEADER | - AS_NODE_TO_XML_FLAG_FORMAT_INDENT | - AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE, - NULL, error); + /* success */ + return TRUE; } -static AsApp * -fu_engine_store_get_app_by_guids (AsStore *store, FuDevice *device) +static XbNode * +fu_engine_store_get_app_by_guids (XbSilo *silo, FuDevice *device) { GPtrArray *guids = fu_device_get_guids (device); for (guint i = 0; i < guids->len; i++) { - AsApp *app = NULL; - app = as_store_get_app_by_provide (store, - AS_PROVIDE_KIND_FIRMWARE_FLASHED, - g_ptr_array_index (guids, i)); - if (app != NULL) - return app; + g_autoptr(XbNode) component = NULL; + g_autofree gchar *xpath = NULL; + const gchar *guid = g_ptr_array_index (guids, i); + xpath = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../..", + guid); + component = xb_silo_query_first (silo, xpath, NULL); + if (component != NULL) + return g_steal_pointer (&component); } return NULL; } @@ -604,22 +653,24 @@ fu_engine_store_get_app_by_guids (AsStore *store, FuDevice *device) * @device_id: A device ID * @error: A #GError, or %NULL * - * Verifies a device firmware checksum using the verification store entry. + * Verifies a device firmware checksum using the verification silo entry. * * Returns: %TRUE for success **/ gboolean fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) { - AsApp *app; - AsChecksum *csum; - AsRelease *release; FuPlugin *plugin; GPtrArray *checksums; const gchar *hash = NULL; - const gchar *version = NULL; - g_autoptr(AsStore) store = NULL; + const gchar *version; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; g_autoptr(FuDevice) device = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) release = NULL; + g_autoptr(XbSilo) silo = xb_silo_new (); g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -643,32 +694,42 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) return FALSE; /* find component in metadata */ - store = fu_engine_load_verify_store (error); - if (store == NULL) - return FALSE; - app = fu_engine_store_get_app_by_guids (store, device); - if (app == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No metadata"); - return FALSE; + version = fu_device_get_version (device); + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id); + file = g_file_new_for_path (fn); + if (g_file_query_exists (file, NULL)) { + g_autofree gchar *xpath = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, + XB_BUILDER_COMPILE_FLAG_NONE, + NULL, error); + if (silo == NULL) + return FALSE; + xpath = g_strdup_printf ("component/releases/release[@version='%s']", version); + release = xb_silo_query_first (silo, xpath, NULL); } - /* find version in metadata */ - version = fu_device_get_version (device); - release = as_app_get_release (app, version); + /* try again with the system metadata */ if (release == NULL) { - /* try again with the system metadata */ - app = fu_engine_store_get_app_by_guids (self->store, device); - if (app == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No system metadata"); - return FALSE; + GPtrArray *guids = fu_device_get_guids (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autofree gchar *xpath2 = NULL; + xpath2 = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../../releases/release[@version='%s']", + guid, version); + release = xb_silo_query_first (self->silo, xpath2, NULL); + if (release != NULL) + break; } - release = as_app_get_release (app, version); } if (release == NULL) { g_set_error (error, @@ -679,7 +740,7 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) } /* find checksum */ - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); + csum = xb_node_query_first (release, "checksum[@target='content']", NULL); if (csum == NULL) { g_set_error (error, FWUPD_ERROR, @@ -700,7 +761,7 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) for (guint j = 0; j < checksums->len; j++) { const gchar *hash_tmp = g_ptr_array_index (checksums, j); GChecksumType hash_kind = fwupd_checksum_guess_kind (hash_tmp); - if (as_checksum_get_kind (csum) == hash_kind) { + if (fwupd_checksum_guess_kind (xb_node_get_text (csum)) == hash_kind) { hash = hash_tmp; break; } @@ -712,13 +773,13 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) "No matching hash kind for %s", version); return FALSE; } - if (g_strcmp0 (as_checksum_get_value (csum), hash) != 0) { + if (g_strcmp0 (xb_node_get_text (csum), hash) != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "For v%s expected %s, got %s", version, - as_checksum_get_value (csum), + xb_node_get_text (csum), hash); return FALSE; } @@ -727,46 +788,73 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) return TRUE; } -static GPtrArray * -_as_store_get_apps_by_provide (AsStore *store, AsProvideKind kind, const gchar *value) +static gboolean +fu_engine_require_vercmp (XbNode *req, const gchar *version, GError **error) { -#if AS_CHECK_VERSION(0,7,5) - return as_store_get_apps_by_provide (store, kind, value); -#else - GPtrArray *apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - GPtrArray *array = as_store_get_apps (store); - for (guint i = 0; i < array->len; i++) { - AsApp *app = g_ptr_array_index (array, i); - GPtrArray *provides = as_app_get_provides (app); - for (guint j = 0; j < provides->len; j++) { - AsProvide *tmp = g_ptr_array_index (provides, j); - if (kind != as_provide_get_kind (tmp)) - continue; - if (g_strcmp0 (as_provide_get_value (tmp), value) != 0) - continue; - g_ptr_array_add (apps, g_object_ref (app)); - } + gboolean ret = FALSE; + gint rc = 0; + const gchar *tmp = xb_node_get_attr (req, "compare"); + const gchar *version_req = xb_node_get_attr (req, "version"); + + if (g_strcmp0 (tmp, "eq") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc == 0; + } else if (g_strcmp0 (tmp, "ne") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc != 0; + } else if (g_strcmp0 (tmp, "lt") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc < 0; + } else if (g_strcmp0 (tmp, "gt") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc > 0; + } else if (g_strcmp0 (tmp, "le") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc <= 0; + } else if (g_strcmp0 (tmp, "ge") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc >= 0; + } else if (g_strcmp0 (tmp, "glob") == 0) { + ret = fnmatch (version_req, version, 0) == 0; + } else if (g_strcmp0 (tmp, "regex") == 0) { + ret = g_regex_match_simple (version_req, version, 0, 0); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to compare [%s] and [%s]", + version_req, + version); + return FALSE; } - return apps; -#endif + + /* set error */ + if (!ret) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed predicate [%s %s %s]", + version_req, tmp, version); + } + return ret; } static gboolean -fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, +fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, FuDevice *device, GError **error) { g_autoptr(GError) error_local = NULL; /* old firmware version */ - if (as_require_get_value (req) == NULL) { + if (xb_node_get_text (req) == NULL) { const gchar *version = fu_device_get_version (device); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!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 firmware version %s, requires >= %s", - version, as_require_get_version (req)); + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -780,15 +868,15 @@ fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, } /* bootloader version */ - if (g_strcmp0 (as_require_get_value (req), "bootloader") == 0) { + if (g_strcmp0 (xb_node_get_text (req), "bootloader") == 0) { const gchar *version = fu_device_get_version_bootloader (device); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!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 bootloader version %s, requires >= %s", - version, as_require_get_version (req)); + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -802,15 +890,15 @@ fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, } /* vendor ID */ - if (g_strcmp0 (as_require_get_value (req), "vendor-id") == 0) { + if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0) { const gchar *version = fu_device_get_vendor_id (device); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!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 vendor %s, requires >= %s", - version, as_require_get_version (req)); + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -824,8 +912,8 @@ fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, } /* another device */ - if (fu_common_guid_is_valid (as_require_get_value (req))) { - const gchar *guid = as_require_get_value (req); + if (fu_common_guid_is_valid (xb_node_get_text (req))) { + const gchar *guid = xb_node_get_text (req); const gchar *version; g_autoptr(FuDevice) device2 = NULL; @@ -836,15 +924,15 @@ fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, /* get the version of the other device */ version = fu_device_get_version (device2); - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!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), version, - as_require_get_version (req)); + xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -863,57 +951,57 @@ fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "cannot handle firmware requirement %s", - as_require_get_value (req)); + "cannot handle firmware requirement '%s'", + xb_node_get_text (req)); return FALSE; } static gboolean -fu_engine_check_requirement_id (FuEngine *self, AsRequire *req, GError **error) +fu_engine_check_requirement_id (FuEngine *self, XbNode *req, GError **error) { g_autoptr(GError) error_local = NULL; const gchar *version = g_hash_table_lookup (self->runtime_versions, - as_require_get_value (req)); + xb_node_get_text (req)); if (version == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no version available for %s", - as_require_get_value (req)); + xb_node_get_text (req)); return FALSE; } - if (!as_require_version_compare (req, version, &error_local)) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + if (!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", - as_require_get_value (req), version, - as_require_get_version (req)); + xb_node_get_text (req), version, + xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with %s version: %s", - as_require_get_value (req), error_local->message); + xb_node_get_text (req), error_local->message); } return FALSE; } g_debug ("requirement %s %s %s on %s passed", - as_require_get_version (req), - as_require_compare_to_string (as_require_get_compare (req)), - version, as_require_get_value (req)); + xb_node_get_attr (req, "version"), + xb_node_get_attr (req, "compare"), + version, xb_node_get_text (req)); return TRUE; } static gboolean -fu_engine_check_requirement_hardware (FuEngine *self, AsRequire *req, GError **error) +fu_engine_check_requirement_hardware (FuEngine *self, XbNode *req, GError **error) { g_auto(GStrv) hwid_split = NULL; /* split and treat as OR */ - hwid_split = g_strsplit (as_require_get_value (req), "|", -1); + hwid_split = g_strsplit (xb_node_get_text (req), "|", -1); for (guint i = 0; hwid_split[i] != NULL; i++) { if (fu_hwids_has_guid (self->hwids, hwid_split[i])) { g_debug ("HWID provided %s", hwid_split[i]); @@ -926,26 +1014,26 @@ fu_engine_check_requirement_hardware (FuEngine *self, AsRequire *req, GError **e FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "no HWIDs matched %s", - as_require_get_value (req)); + xb_node_get_text (req)); return FALSE; } static gboolean -fu_engine_check_requirement (FuEngine *self, AsRequire *req, FuDevice *device, GError **error) +fu_engine_check_requirement (FuEngine *self, XbNode *req, FuDevice *device, GError **error) { /* ensure component requirement */ - if (as_require_get_kind (req) == AS_REQUIRE_KIND_ID) + if (g_strcmp0 (xb_node_get_element (req), "id") == 0) return fu_engine_check_requirement_id (self, req, error); /* ensure firmware requirement */ - if (as_require_get_kind (req) == AS_REQUIRE_KIND_FIRMWARE) { + if (g_strcmp0 (xb_node_get_element (req), "firmware") == 0) { if (device == NULL) return TRUE; return fu_engine_check_requirement_firmware (self, req, device, error); } /* ensure hardware requirement */ - if (as_require_get_kind (req) == AS_REQUIRE_KIND_HARDWARE) + if (g_strcmp0 (xb_node_get_element (req), "hardware") == 0) return fu_engine_check_requirement_hardware (self, req, error); /* not supported */ @@ -953,7 +1041,7 @@ fu_engine_check_requirement (FuEngine *self, AsRequire *req, FuDevice *device, G FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "cannot handle requirement type %s", - as_require_kind_to_string (as_require_get_kind (req))); + xb_node_get_element (req)); return FALSE; } @@ -961,8 +1049,9 @@ gboolean fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, FwupdInstallFlags flags, GError **error) { - GPtrArray *reqs = as_app_get_requires (fu_install_task_get_app (task)); FuDevice *device = fu_install_task_get_device (task); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) reqs = NULL; /* all install task checks require a device */ if (device != NULL) { @@ -971,118 +1060,38 @@ fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, } /* do engine checks */ + reqs = xb_node_query (fu_install_task_get_component (task), + "requires/*", 0, &error_local); + if (reqs == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return TRUE; + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + return TRUE; + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } for (guint i = 0; i < reqs->len; i++) { - AsRequire *req = g_ptr_array_index (reqs, i); + XbNode *req = g_ptr_array_index (reqs, i); if (!fu_engine_check_requirement (self, req, device, error)) return FALSE; } return TRUE; } -static void -fu_engine_vendor_fixup_provide_value (AsApp *app) -{ - GPtrArray *provides; - - /* no quirk required */ - if (as_app_get_kind (app) != AS_APP_KIND_FIRMWARE) - return; - - /* fix each provide to be a GUID */ - provides = as_app_get_provides (app); - for (guint i = 0; i < provides->len; i++) { - AsProvide *prov = g_ptr_array_index (provides, i); - const gchar *value = as_provide_get_value (prov); - g_autofree gchar *guid = NULL; - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - if (fu_common_guid_is_valid (value)) - continue; - guid = fu_common_guid_from_string (value); - as_provide_set_value (prov, guid); - } -} - -static void -fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app) -{ - FuVersionFormat flags = FU_VERSION_FORMAT_TRIPLET; - GPtrArray *releases; - const gchar *quirk; - const gchar *version_format; - - /* no quirk required */ - if (as_app_get_kind (app) != AS_APP_KIND_FIRMWARE) - return; - - /* fall back to the quirk database until all files have metadata */ - quirk = fu_quirks_lookup_by_id (self->quirks, - "DaemonVersionFormat=quad", - FU_QUIRKS_DAEMON_VERSION_FORMAT); - if (quirk != NULL) { - g_auto(GStrv) globs = g_strsplit (quirk, ",", -1); - for (guint i = 0; globs[i] != NULL; i++) { - if (fnmatch (globs[i], as_app_get_id (app), 0) == 0) { - flags = FU_VERSION_FORMAT_QUAD; - break; - } - } - } - - /* specified in metadata */ - version_format = as_app_get_metadata_item (app, "LVFS::VersionFormat"); - if (g_strcmp0 (version_format, "quad") == 0) - flags = FU_VERSION_FORMAT_QUAD; - - /* fix each release */ - releases = as_app_get_releases (app); - for (guint i = 0; i < releases->len; i++) { - AsRelease *rel; - const gchar *version; - guint64 ver_uint32; - g_autofree gchar *version_new = NULL; - - rel = g_ptr_array_index (releases, i); - version = as_release_get_version (rel); - if (version == NULL) - continue; - if (g_strstr_len (version, -1, ".") != NULL) - continue; - - /* metainfo files use hex and the LVFS uses decimal */ - ver_uint32 = fu_common_strtoull (version); - if (ver_uint32 == 0) - continue; - - /* convert to dotted decimal */ - version_new = fu_common_version_from_uint32 ((guint32) ver_uint32, flags); - as_release_set_version (rel, version_new); - } -} - static gchar * -fu_engine_get_guids_from_store (AsStore *store) +fu_engine_get_guids_from_store (XbSilo *silo) { - AsProvide *prov; - GPtrArray *provides; - GPtrArray *apps; - GString *str = g_string_new (""); + GString *str; + g_autoptr(GPtrArray) provides = NULL; - /* return a string with all the firmware apps in the store */ - apps = as_store_get_apps (store); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = AS_APP (g_ptr_array_index (apps, i)); - provides = as_app_get_provides (app); - for (guint j = 0; j < provides->len; j++) { - prov = AS_PROVIDE (g_ptr_array_index (provides, j)); - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - g_string_append_printf (str, "%s,", as_provide_get_value (prov)); - } - } - if (str->len == 0) { - g_string_free (str, TRUE); + /* return a string with all the firmware components in the silo */ + provides = xb_silo_query (silo, "components/component/provides/firmware[@type='flashed']", 0, NULL); + if (provides == NULL) return NULL; + str = g_string_new (NULL); + for (guint i = 0; i < provides->len; i++) { + XbNode *prov = XB_NODE (g_ptr_array_index (provides, i)); + g_string_append_printf (str, "%s,", xb_node_get_text (prov)); } g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); @@ -1295,27 +1304,28 @@ fu_engine_install (FuEngine *self, FwupdInstallFlags flags, GError **error) { - AsApp *app = fu_install_task_get_app (task); - AsChecksum *csum_tmp; - AsRelease *rel; + XbNode *component = fu_install_task_get_component (task); FuDevice *device = fu_install_task_get_device (task); GBytes *blob_fw; - const gchar *tmp; - const gchar *version; + const gchar *tmp = NULL; + g_autofree gchar *release_key = NULL; + g_autofree gchar *version_rel = NULL; g_autoptr(GBytes) blob_fw2 = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(XbNode) rel = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (AS_IS_APP (app), 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 */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { const gchar *caption = NULL; - AsScreenshot *ss = as_app_get_screenshot_default (app); - if (ss != NULL) - caption = as_screenshot_get_caption (ss, NULL); + caption = xb_node_query_text (component, + "screenshots/screenshot/caption", + NULL); if (caption != NULL) { g_set_error (error, FWUPD_ERROR, @@ -1333,40 +1343,36 @@ fu_engine_install (FuEngine *self, } /* parse the DriverVer */ - rel = as_app_get_release_default (app); + rel = xb_node_query_first (component, "releases/release", &error_local); if (rel == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No releases in the firmware component"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "No releases in the firmware component: %s", + error_local->message); return FALSE; } /* get the blob */ - csum_tmp = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - tmp = as_checksum_get_filename (csum_tmp); - if (tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No checksum filename"); - return FALSE; - } + tmp = xb_node_query_attr (rel, "checksum[@target='content']", "filename", NULL); + if (tmp == NULL) + tmp = "firmware.bin"; /* not all devices have to use the same blob */ - blob_fw = as_release_get_blob (rel, tmp); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", tmp); + blob_fw = xb_node_get_data (rel, release_key); if (blob_fw == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "Failed to get firmware blob"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "Failed to get firmware blob using %s", tmp); return FALSE; } /* use a bubblewrap helper script to build the firmware */ - tmp = as_app_get_metadata_item (app, "fwupd::BuilderScript"); + tmp = g_object_get_data (G_OBJECT (component), "fwupd::BuilderScript"); if (tmp != NULL) { - const gchar *tmp2 = as_app_get_metadata_item (app, "fwupd::BuilderOutput"); + 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); @@ -1377,9 +1383,9 @@ fu_engine_install (FuEngine *self, } /* install firmware blob */ - version = as_release_get_version (rel); + version_rel = fu_engine_get_release_version (self, component, rel); return fu_engine_install_blob (self, device, blob_cab, blob_fw2, - version, flags, error); + version_rel, flags, error); } /** @@ -1727,95 +1733,33 @@ fu_engine_get_item_by_id_fallback_history (FuEngine *self, const gchar *id, GErr return NULL; } -/* add releases that do not exist from a higher priority remote */ -static void -fu_engine_merge_component_releases (AsApp *app_old, AsApp *app) +/* for the self tests */ +void +fu_engine_set_silo (FuEngine *self, XbSilo *silo) { - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - AsRelease *release_old; - const gchar *version = as_release_get_version (release); - release_old = as_app_get_release_by_version (app_old, version); - if (release_old != NULL) - continue; - g_debug ("adding release %s to existing %s", - version, as_app_get_id (app_old)); - as_app_add_release (app_old, release); - } -} - -gboolean -fu_engine_load_metadata_from_file (FuEngine *self, - const gchar *path, - const gchar *remote_id, - GError **error) -{ - GPtrArray *apps; - g_autoptr(AsStore) store = NULL; - g_autoptr(GFile) file = NULL; - g_autoptr(GBytes) remote_blob = NULL; - g_autoptr(GPtrArray) apps_new = NULL; - - /* load the store locally until we know it is valid */ - store = as_store_new (); - file = g_file_new_for_path (path); - if (!as_store_from_file (store, file, NULL, NULL, error)) - return FALSE; - - /* save the remote to the release */ - if (remote_id != NULL && remote_id[0] != '\0') - remote_blob = g_bytes_new (remote_id, strlen (remote_id) + 1); - - /* add the new application from the store */ - apps = as_store_get_apps (store); - apps_new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); - AsApp *app_old = as_store_get_app_by_id (self->store, as_app_get_id (app)); - - /* save the remote-id to all the releases for this component */ - if (remote_blob != NULL) { - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - as_release_set_blob (release, - "fwupd::RemoteId", - remote_blob); - } - } - - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); - - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); - - /* merge in new releases if already known */ - if (app_old != NULL) { - fu_engine_merge_component_releases (app_old, app); - continue; - } - g_ptr_array_add (apps_new, g_object_ref (app)); - } - - /* add in one operation to avoid 'n' "Emitting ::changed()" events */ - as_store_add_apps (self->store, apps_new); - return TRUE; + g_return_if_fail (FU_IS_ENGINE (self)); + g_return_if_fail (XB_IS_SILO (silo)); + g_set_object (&self->silo, silo); } static gboolean fu_engine_is_device_supported (FuEngine *self, FuDevice *device) { - AsApp *app; + g_autoptr(XbNode) component = NULL; + + /* sanity check */ + if (self->silo == NULL) { + g_critical ("FuEngine silo not set up"); + return FALSE; + } /* no device version */ if (fu_device_get_version (device) == NULL) return FALSE; /* match the GUIDs in the XML */ - app = fu_engine_store_get_app_by_guids (self->store, device); - if (app == NULL) + component = fu_engine_store_get_app_by_guids (self->silo, device); + if (component == NULL) return FALSE; /* success */ @@ -1826,17 +1770,33 @@ static gboolean fu_engine_load_metadata_store (FuEngine *self, GError **error) { GPtrArray *remotes; + g_autofree gchar *cachedirpkg = NULL; g_autofree gchar *guids_str = NULL; + g_autofree gchar *xmlbfn = NULL; + g_autoptr(GFile) xmlb = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); - /* clear existing store */ - as_store_remove_all (self->store); + /* clear existing silo */ + g_clear_object (&self->silo); + + /* verbose profiling */ + if (g_getenv ("FWUPD_VERBOSE") != NULL) { + xb_builder_set_profile_flags (builder, + XB_SILO_PROFILE_FLAG_XPATH | + XB_SILO_PROFILE_FLAG_DEBUG); + } /* load each enabled metadata file */ remotes = fu_config_get_remotes (self->config); for (guint i = 0; i < remotes->len; i++) { const gchar *path = NULL; g_autoptr(GError) error_local = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilderNode) custom = NULL; + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + FwupdRemote *remote = g_ptr_array_index (remotes, i); if (!fwupd_remote_get_enabled (remote)) { g_debug ("remote %s not enabled, so skipping", @@ -1848,22 +1808,47 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) g_debug ("no %s, so skipping", path); continue; } - if (!fu_engine_load_metadata_from_file (self, path, - fwupd_remote_get_id (remote), - &error_local)) { + + /* save the remote-id in the custom metadata space */ + custom = xb_builder_node_new ("custom"); + xb_builder_node_insert_text (custom, + "fwupd::FilenameCache", path, + NULL); + xb_builder_node_insert_text (custom, + "fwupd::RemoteId", fwupd_remote_get_id (remote), + NULL); + file = g_file_new_for_path (path); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, &error_local)) { g_warning ("failed to load remote %s: %s", fwupd_remote_get_id (remote), error_local->message); continue; } + + /* we need to watch for changes? */ + xb_builder_import_source (builder, source); } + /* ensure silo is up to date */ + cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); + xmlbfn = g_build_filename (cachedirpkg, "metadata.xmlb", NULL); + xmlb = g_file_new_for_path (xmlbfn); + self->silo = xb_builder_ensure (builder, xmlb, + XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID, + NULL, error); + if (self->silo == NULL) + return FALSE; + /* print what we've got */ - g_debug ("%u components now in store", as_store_get_size (self->store)); + components = xb_silo_query (self->silo, "components/component", 0, NULL); + if (components != NULL) + g_debug ("%u components now in silo", components->len); /* update the list of supported GUIDs */ g_ptr_array_set_size (self->supported_guids, 0); - guids_str = fu_engine_get_guids_from_store (self->store); + guids_str = fu_engine_get_guids_from_store (self->silo); if (guids_str != NULL) { g_auto(GStrv) guids = g_strsplit (guids_str, ",", -1); for (guint i = 0; guids[i] != NULL; i++) { @@ -2044,21 +2029,19 @@ fu_engine_update_metadata (FuEngine *self, const gchar *remote_id, } /** - * fu_engine_get_store_from_blob: + * fu_engine_get_silo_from_blob: * @self: A #FuEngine * @blob_cab: A #GBytes * @error: A #GError, or %NULL * - * Creates an AppStream store from a .cab file blob. + * Creates a silo from a .cab file blob. * - * Returns: (transfer container): a #AsStore, or %NULL + * Returns: (transfer container): a #XbSilo, or %NULL **/ -AsStore * -fu_engine_get_store_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) +XbSilo * +fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) { - GPtrArray *apps; - g_autofree gchar *checksum = NULL; - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), NULL); g_return_val_if_fail (blob_cab != NULL, NULL); @@ -2066,56 +2049,47 @@ fu_engine_get_store_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) /* load file */ fu_engine_set_status (self, FWUPD_STATUS_DECOMPRESSING); - store = fu_common_store_from_cab_bytes (blob_cab, - fu_engine_get_archive_size_max (self), - error); - if (store == NULL) + silo = fu_common_cab_build_silo (blob_cab, + fu_engine_get_archive_size_max (self), + error); + if (silo == NULL) return NULL; - /* fix all the apps */ - apps = as_store_get_apps (store); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); - - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); - - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); - } - - /* get a checksum of the file and use it as the origin */ - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, blob_cab); - as_store_set_origin (store, checksum); - fu_engine_set_status (self, FWUPD_STATUS_IDLE); - return g_steal_pointer (&store); + return g_steal_pointer (&silo); } static FwupdDevice * -fu_engine_get_result_from_app (FuEngine *self, AsApp *app, GError **error) +fu_engine_get_result_from_app (FuEngine *self, XbNode *component, GError **error) { FwupdTrustFlags trust_flags = FWUPD_TRUST_FLAG_NONE; - AsRelease *release; - GPtrArray *provides; g_autoptr(FuInstallTask) task = NULL; g_autoptr(FwupdDevice) dev = NULL; g_autoptr(FwupdRelease) rel = NULL; g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) provides = NULL; + g_autoptr(XbNode) description = NULL; + g_autoptr(XbNode) release = NULL; dev = fwupd_device_new (); - provides = as_app_get_provides (app); + provides = xb_node_query (component, + "provides/firmware[@type='flashed']", + 0, &error_local); + if (provides == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to get release: %s", + error_local->message); + return NULL; + } for (guint i = 0; i < provides->len; i++) { - AsProvide *prov = AS_PROVIDE (g_ptr_array_index (provides, i)); + XbNode *prov = XB_NODE (g_ptr_array_index (provides, i)); const gchar *guid; g_autoptr(FuDevice) device = NULL; - /* not firmware */ - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - /* is a online or offline update appropriate */ - guid = as_provide_get_value (prov); + guid = xb_node_get_text (prov); if (guid == NULL) continue; device = fu_device_list_get_by_guid (self->device_list, guid, NULL); @@ -2137,14 +2111,24 @@ fu_engine_get_result_from_app (FuEngine *self, AsApp *app, GError **error) } /* check we can install it */ - task = fu_install_task_new (NULL, app); + task = fu_install_task_new (NULL, component); if (!fu_engine_check_requirements (self, task, FWUPD_INSTALL_FLAG_NONE, error)) return NULL; /* verify trust */ - release = as_app_get_release_default (app); + release = xb_node_query_first (component, + "releases/release", + &error_local); + if (release == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to get release: %s", + error_local->message); + return NULL; + } if (!fu_keyring_get_release_trust_flags (release, &trust_flags, &error_local)) { @@ -2160,10 +2144,18 @@ fu_engine_get_result_from_app (FuEngine *self, AsApp *app, GError **error) } /* create a result with all the metadata in */ - fwupd_device_set_description (dev, as_app_get_description (app, NULL)); + description = xb_node_query_first (component, "description", NULL); + if (description != NULL) { + g_autofree gchar *xml = NULL; + xml = xb_node_export (description, + XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, + NULL); + if (xml != NULL) + fwupd_device_set_description (dev, xml); + } rel = fwupd_release_new (); fwupd_release_set_trust_flags (rel, trust_flags); - fu_engine_set_release_from_appstream (self, rel, app, release); + fu_engine_set_release_from_appstream (self, rel, component, release); fwupd_device_add_release (dev, rel); return g_steal_pointer (&dev); } @@ -2183,32 +2175,34 @@ fu_engine_get_result_from_app (FuEngine *self, AsApp *app, GError **error) GPtrArray * fu_engine_get_details (FuEngine *self, gint fd, GError **error) { - GPtrArray *apps; const gchar *remote_id; g_autofree gchar *csum = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) details = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), NULL); g_return_val_if_fail (fd > 0, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - /* get all apps */ + /* get all components */ blob = fu_common_get_contents_fd (fd, fu_engine_get_archive_size_max (self), error); if (blob == NULL) return NULL; - store = fu_engine_get_store_from_blob (self, blob, error); - if (store == NULL) + silo = fu_engine_get_silo_from_blob (self, blob, error); + if (silo == NULL) return NULL; - apps = as_store_get_apps (store); - if (apps->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no components"); + components = xb_silo_query (silo, "component", 0, &error_local); + if (components == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no components: %s", + error_local->message); return NULL; } @@ -2218,12 +2212,10 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) /* create results with all the metadata in */ details = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); FwupdDevice *dev; - - as_app_set_origin (app, as_store_get_origin (store)); - dev = fu_engine_get_result_from_app (self, app, error); + dev = fu_engine_get_result_from_app (self, component, error); if (dev == NULL) return NULL; if (remote_id != NULL) { @@ -2373,39 +2365,58 @@ fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b) { FwupdRelease *rel_a = FWUPD_RELEASE (*((FwupdRelease **) a)); FwupdRelease *rel_b = FWUPD_RELEASE (*((FwupdRelease **) b)); - return as_utils_vercmp (fwupd_release_get_version (rel_b), + return fu_common_vercmp (fwupd_release_get_version (rel_b), fwupd_release_get_version (rel_a)); } -static AsApp * -fu_engine_filter_apps_by_requirements (FuEngine *self, GPtrArray *apps, - FuDevice *device, GError **error) +static gboolean +fu_engine_add_releases_for_device_component (FuEngine *self, + FuDevice *device, + XbNode *component, + GPtrArray *releases, + GError **error) { - g_autoptr(GError) error_all = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(FuInstallTask) task = fu_install_task_new (device, component); + g_autoptr(GPtrArray) releases_tmp = NULL; - /* find the first component that passes all the requirements */ - for (guint i = 0; i < apps->len; i++) { - AsApp *app_tmp = AS_APP (g_ptr_array_index (apps, i)); - g_autoptr(GError) error_local = NULL; - g_autoptr(FuInstallTask) task = fu_install_task_new (device, app_tmp); - if (!fu_engine_check_requirements (self, task, - FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | - FWUPD_INSTALL_FLAG_ALLOW_OLDER, - &error_local)) { - if (error_all == NULL) { - error_all = g_steal_pointer (&error_local); - continue; - } - /* assume the domain and code is the same */ - g_prefix_error (&error_all, "%s, ", error_local->message); + if (!fu_engine_check_requirements (self, task, + FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | + FWUPD_INSTALL_FLAG_ALLOW_OLDER, + error)) + return FALSE; + + /* get all releases */ + releases_tmp = xb_node_query (component, "releases/release", 0, &error_local); + if (releases_tmp == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return TRUE; + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + return TRUE; + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + for (guint i = 0; i < releases_tmp->len; i++) { + XbNode *release = g_ptr_array_index (releases_tmp, i); + GPtrArray *checksums; + g_autoptr(FwupdRelease) rel = fwupd_release_new (); + + /* create new FwupdRelease for the XbNode */ + fu_engine_set_release_from_appstream (self, rel, component, release); + + /* invalid */ + if (fwupd_release_get_uri (rel) == NULL) continue; - } - return g_object_ref (app_tmp); + checksums = fwupd_release_get_checksums (rel); + if (checksums->len == 0) + continue; + + /* success */ + g_ptr_array_add (releases, g_steal_pointer (&rel)); } - /* return the compound error */ - g_propagate_error (error, g_steal_pointer (&error_all)); - return NULL; + /* success */ + return TRUE; } static GPtrArray * @@ -2414,6 +2425,10 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er GPtrArray *device_guids; GPtrArray *releases; const gchar *version; + g_autoptr(GError) error_all = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GString) xpath = g_string_new (NULL); /* get device version */ version = fu_device_get_version (device); @@ -2436,46 +2451,52 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er return NULL; } - releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + /* get all the components that provide any of these GUIDs */ device_guids = fu_device_get_guids (device); for (guint i = 0; i < device_guids->len; i++) { - GPtrArray *releases_tmp; - g_autoptr(AsApp) app = NULL; - g_autoptr(GPtrArray) apps = NULL; const gchar *guid = g_ptr_array_index (device_guids, i); - - /* get all the components that provide this GUID */ - apps = _as_store_get_apps_by_provide (self->store, - AS_PROVIDE_KIND_FIRMWARE_FLASHED, - guid); - if (apps->len == 0) - continue; - - /* filter by requirements */ - app = fu_engine_filter_apps_by_requirements (self, apps, device, error); - if (app == NULL) - return NULL; - - /* get all releases */ - releases_tmp = as_app_get_releases (app); - for (guint j = 0; j < releases_tmp->len; j++) { - AsRelease *release = g_ptr_array_index (releases_tmp, j); - GPtrArray *checksums; - g_autoptr(FwupdRelease) rel = fwupd_release_new (); - - /* create new FwupdRelease for the AsRelease */ - fu_engine_set_release_from_appstream (self, rel, app, release); - - /* invalid */ - if (fwupd_release_get_uri (rel) == NULL) - continue; - checksums = fwupd_release_get_checksums (rel); - if (checksums->len == 0) - continue; - - /* success */ - g_ptr_array_add (releases, g_steal_pointer (&rel)); + xb_string_append_union (xpath, + "components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../..", guid); + } + components = xb_silo_query (self->silo, xpath->str, 0, &error_local); + if (components == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No releases found for device"); + return FALSE; } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + + /* find all the releases that pass all the requirements */ + releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < components->len; i++) { + XbNode *component = XB_NODE (g_ptr_array_index (components, i)); + g_autoptr(GError) error_tmp = NULL; + if (!fu_engine_add_releases_for_device_component (self, + device, + component, + releases, + &error_tmp)) { + if (error_all == NULL) { + error_all = g_steal_pointer (&error_tmp); + continue; + } + + /* assume the domain and code is the same */ + g_prefix_error (&error_all, "%s, ", error_tmp->message); + } + } + + /* return the compound error */ + if (releases->len == 0) { + g_propagate_error (error, g_steal_pointer (&error_all)); + return NULL; } return releases; } @@ -2557,7 +2578,7 @@ fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error gint vercmp; /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), + vercmp = fu_common_vercmp (fwupd_release_get_version (rel_tmp), fu_device_get_version (device)); if (vercmp == 0) { g_string_append_printf (error_str, "%s=same, ", @@ -2578,7 +2599,7 @@ fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error /* don't show releases we are not allowed to dowgrade to */ if (fu_device_get_version_lowest (device) != NULL) { - if (as_utils_vercmp (fwupd_release_get_version (rel_tmp), + if (fu_common_vercmp (fwupd_release_get_version (rel_tmp), fu_device_get_version_lowest (device)) <= 0) { g_string_append_printf (error_str, "%s=lowest, ", fwupd_release_get_version (rel_tmp)); @@ -2660,7 +2681,7 @@ fu_engine_get_upgrades (FuEngine *self, const gchar *device_id, GError **error) gint vercmp; /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), + vercmp = fu_common_vercmp (fwupd_release_get_version (rel_tmp), fu_device_get_version (device)); if (vercmp == 0) { g_string_append_printf (error_str, "%s=same, ", @@ -2989,12 +3010,15 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) /* if this device is locked get some metadata from AppStream */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_LOCKED)) { - AsApp *app = fu_engine_store_get_app_by_guids (self->store, device); - if (app != NULL) { - AsRelease *release = as_app_get_release_default (app); + g_autoptr(XbNode) component = fu_engine_store_get_app_by_guids (self->silo, device); + 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 (); - fu_engine_set_release_from_appstream (self, rel, app, release); + fu_engine_set_release_from_appstream (self, rel, component, release); fu_device_add_release (device, rel); } } @@ -3639,7 +3663,6 @@ fu_engine_load (FuEngine *self, GError **error) fu_engine_load_quirks (self); /* load AppStream metadata */ - as_store_add_filter (self->store, AS_APP_KIND_FIRMWARE); if (!fu_engine_load_metadata_store (self, error)) { g_prefix_error (error, "Failed to load AppStream data: "); return FALSE; @@ -3775,7 +3798,6 @@ fu_engine_init (FuEngine *self) self->quirks = fu_quirks_new (); self->history = fu_history_new (); self->plugin_list = fu_plugin_list_new (); - self->store = as_store_new (); self->plugin_filter = g_ptr_array_new_with_free_func (g_free); self->supported_guids = g_ptr_array_new_with_free_func (g_free); self->udev_subsystems = g_ptr_array_new_with_free_func (g_free); @@ -3796,12 +3818,6 @@ fu_engine_init (FuEngine *self) g_hash_table_insert (self->compile_versions, g_strdup ("org.freedesktop.fwupd"), g_strdup (VERSION)); - g_hash_table_insert (self->compile_versions, - g_strdup ("org.freedesktop.appstream-glib"), - g_strdup_printf ("%i.%i.%i", - AS_MAJOR_VERSION, - AS_MINOR_VERSION, - AS_MICRO_VERSION)); g_hash_table_insert (self->compile_versions, g_strdup ("org.freedesktop.gusb"), g_strdup_printf ("%i.%i.%i", @@ -3818,6 +3834,8 @@ fu_engine_finalize (GObject *obj) if (self->usb_ctx != NULL) g_object_unref (self->usb_ctx); + if (self->silo != NULL) + g_object_unref (self->silo); if (self->gudev_client != NULL) g_object_unref (self->gudev_client); if (self->coldplug_id != 0) @@ -3828,7 +3846,6 @@ fu_engine_finalize (GObject *obj) g_object_unref (self->quirks); g_object_unref (self->hwids); g_object_unref (self->history); - g_object_unref (self->store); g_object_unref (self->device_list); g_ptr_array_unref (self->supported_guids); g_ptr_array_unref (self->plugin_filter); diff --git a/src/fu-engine.h b/src/fu-engine.h index f271ed680..d276206f2 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -9,7 +9,7 @@ G_BEGIN_DECLS -#include +#include #include #include "fwupd-device.h" @@ -30,7 +30,7 @@ gboolean fu_engine_load (FuEngine *self, gboolean fu_engine_load_plugins (FuEngine *self, GError **error); FwupdStatus fu_engine_get_status (FuEngine *self); -AsStore *fu_engine_get_store_from_blob (FuEngine *self, +XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error); guint64 fu_engine_get_archive_size_max (FuEngine *self); @@ -122,10 +122,8 @@ gboolean fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, FwupdInstallFlags flags, GError **error); -gboolean fu_engine_load_metadata_from_file (FuEngine *self, - const gchar *path, - const gchar *remote_id, - GError **error); +void fu_engine_set_silo (FuEngine *self, + XbSilo *silo); G_END_DECLS diff --git a/src/fu-install-task.c b/src/fu-install-task.c index 851abe0bb..06787a53e 100644 --- a/src/fu-install-task.c +++ b/src/fu-install-task.c @@ -19,7 +19,7 @@ struct _FuInstallTask { GObject parent_instance; FuDevice *device; - AsApp *app; + XbNode *component; FwupdTrustFlags trust_flags; gboolean is_downgrade; }; @@ -42,18 +42,18 @@ fu_install_task_get_device (FuInstallTask *self) } /** - * fu_install_task_get_app: + * fu_install_task_get_component: * @self: A #FuInstallTask * * Gets the component for this task. * * Returns: (transfer none): the component **/ -AsApp * -fu_install_task_get_app (FuInstallTask *self) +XbNode * +fu_install_task_get_component (FuInstallTask *self) { g_return_val_if_fail (FU_IS_INSTALL_TASK (self), NULL); - return self->app; + return self->component; } /** @@ -109,25 +109,33 @@ fu_install_task_check_requirements (FuInstallTask *self, FwupdInstallFlags flags, GError **error) { - AsRelease *release; - GPtrArray *provides; const gchar *version; const gchar *version_release; const gchar *version_lowest; gboolean matches_guid = FALSE; gint vercmp; g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) provides = NULL; + g_autoptr(XbNode) release = NULL; g_return_val_if_fail (FU_IS_INSTALL_TASK (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - /* does this app provide a GUID the device has */ - provides = as_app_get_provides (self->app); + /* 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++) { - AsProvide *provide = g_ptr_array_index (provides, i); - if (as_provide_get_kind (provide) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - if (fu_device_has_guid (self->device, as_provide_get_value (provide))) { + XbNode *provide = g_ptr_array_index (provides, i); + if (fu_device_has_guid (self->device, xb_node_get_text (provide))) { matches_guid = TRUE; break; } @@ -187,7 +195,7 @@ fu_install_task_check_requirements (FuInstallTask *self, } /* get latest release */ - release = as_app_get_release_default (self->app); + release = xb_node_query_first (self->component, "releases/release", NULL); if (release == NULL) { g_set_error (error, FWUPD_ERROR, @@ -199,7 +207,7 @@ fu_install_task_check_requirements (FuInstallTask *self, } /* is this a downgrade or re-install */ - version_release = as_release_get_version (release); + version_release = xb_node_get_attr (release, "version"); if (version_release == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -294,7 +302,7 @@ fu_install_task_finalize (GObject *object) { FuInstallTask *self = FU_INSTALL_TASK (object); - g_object_unref (self->app); + g_object_unref (self->component); if (self->device != NULL) g_object_unref (self->device); @@ -332,18 +340,18 @@ fu_install_task_compare (FuInstallTask *task1, FuInstallTask *task2) /** * fu_install_task_new: * @device: A #FuDevice - * @app: a #AsApp + * @component: a #XbNode * * Creates a new install task that may or may not be valid. * * Returns: (transfer full): the #FuInstallTask **/ FuInstallTask * -fu_install_task_new (FuDevice *device, AsApp *app) +fu_install_task_new (FuDevice *device, XbNode *component) { FuInstallTask *self; self = g_object_new (FU_TYPE_TASK, NULL); - self->app = g_object_ref (app); + 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 index d3bbe45ca..c57178a3d 100644 --- a/src/fu-install-task.h +++ b/src/fu-install-task.h @@ -8,7 +8,7 @@ #define __FU_INSTALL_TASK_H #include -#include +#include #include "fu-device.h" @@ -18,9 +18,9 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (FuInstallTask, fu_install_task, FU, INSTALL_TASK, GObject) FuInstallTask *fu_install_task_new (FuDevice *device, - AsApp *app); + XbNode *component); FuDevice *fu_install_task_get_device (FuInstallTask *self); -AsApp *fu_install_task_get_app (FuInstallTask *self); +XbNode *fu_install_task_get_component (FuInstallTask *self); FwupdTrustFlags 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, diff --git a/src/fu-keyring-utils.c b/src/fu-keyring-utils.c index 0c5a7f04a..a3f1936a7 100644 --- a/src/fu-keyring-utils.c +++ b/src/fu-keyring-utils.c @@ -67,7 +67,7 @@ fu_keyring_create_for_kind (FwupdKeyringKind kind, GError **error) /** * fu_keyring_get_release_trust_flags: - * @release: A #AsRelease, e.g. %FWUPD_KEYRING_KIND_GPG + * @release: A #XbNode, e.g. %FWUPD_KEYRING_KIND_GPG * @trust_flags: A #FwupdTrustFlags, e.g. %FWUPD_TRUST_FLAG_PAYLOAD * @error: A #GError, or %NULL * @@ -76,16 +76,16 @@ fu_keyring_create_for_kind (FwupdKeyringKind kind, GError **error) * Returns: %TRUE if @trust_flags has been set **/ gboolean -fu_keyring_get_release_trust_flags (AsRelease *release, +fu_keyring_get_release_trust_flags (XbNode *release, FwupdTrustFlags *trust_flags, GError **error) { - AsChecksum *csum_tmp; FwupdKeyringKind keyring_kind = FWUPD_KEYRING_KIND_UNKNOWN; GBytes *blob_payload; GBytes *blob_signature; const gchar *fn; g_autofree gchar *pki_dir = NULL; + g_autofree gchar *release_key = NULL; g_autofree gchar *sysconfdir = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(FuKeyring) kr = NULL; @@ -100,28 +100,17 @@ fu_keyring_get_release_trust_flags (AsRelease *release, { FWUPD_KEYRING_KIND_NONE, NULL } }; - /* no filename? */ - csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum_tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no content checksum for release"); - return FALSE; - } - fn = as_checksum_get_filename (csum_tmp); - if (fn == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no filename"); - return FALSE; - } + /* custom filename specified */ + fn = xb_node_query_attr (release, "checksum[@target='content']", "filename", NULL); + if (fn == NULL) + fn = "filename.bin"; /* no signature == no trust */ for (guint i = 0; keyrings[i].ext != NULL; i++) { - g_autofree gchar *fn_tmp = g_strdup_printf ("%s.%s", fn, keyrings[i].ext); - blob_signature = as_release_get_blob (release, fn_tmp); + g_autofree gchar *fn_tmp = NULL; + fn_tmp = g_strdup_printf ("fwupd::ReleaseBlob(%s.%s)", + fn, keyrings[i].ext); + blob_signature = g_object_get_data (G_OBJECT (release), fn_tmp); if (blob_signature != NULL) { keyring_kind = keyrings[i].kind; break; @@ -133,7 +122,8 @@ fu_keyring_get_release_trust_flags (AsRelease *release, } /* get payload */ - blob_payload = as_release_get_blob (release, fn); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", fn); + blob_payload = g_object_get_data (G_OBJECT (release), release_key); if (blob_payload == NULL) { g_set_error_literal (error, FWUPD_ERROR, diff --git a/src/fu-keyring-utils.h b/src/fu-keyring-utils.h index fa5ff34ca..43551b010 100644 --- a/src/fu-keyring-utils.h +++ b/src/fu-keyring-utils.h @@ -7,14 +7,14 @@ #ifndef __FU_KEYRING_UTILS_H__ #define __FU_KEYRING_UTILS_H__ -#include +#include #include "fu-keyring.h" #include "fwupd-enums.h" FuKeyring *fu_keyring_create_for_kind (FwupdKeyringKind kind, GError **error); -gboolean fu_keyring_get_release_trust_flags (AsRelease *release, +gboolean fu_keyring_get_release_trust_flags (XbNode *release, FwupdTrustFlags *trust_flags, GError **error); diff --git a/src/fu-main.c b/src/fu-main.c index 4d36ec04f..b28ea9015 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -8,7 +8,7 @@ #include "config.h" -#include +#include #include #include #include @@ -298,6 +298,7 @@ typedef struct { gchar *remote_id; gchar *key; gchar *value; + XbSilo *silo; } FuMainAuthHelper; static void @@ -307,6 +308,8 @@ fu_main_auth_helper_free (FuMainAuthHelper *helper) g_bytes_unref (helper->blob_cab); if (helper->subject != NULL) g_object_unref (helper->subject); + if (helper->silo != NULL) + g_object_unref (helper->silo); if (helper->install_tasks != NULL) g_ptr_array_unref (helper->install_tasks); if (helper->action_ids != NULL) @@ -568,9 +571,8 @@ static gboolean fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) { FuMainPrivate *priv = helper_ref->priv; - GPtrArray *apps; - g_autoptr(AsStore) store = NULL; g_autoptr(FuMainAuthHelper) helper = helper_ref; + g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) devices_possible = NULL; g_autoptr(GPtrArray) errors = NULL; @@ -585,20 +587,22 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) return FALSE; } - /* parse store */ - store = fu_engine_get_store_from_blob (priv->engine, - helper->blob_cab, - error); - if (store == NULL) + /* parse silo */ + helper->silo = fu_engine_get_silo_from_blob (priv->engine, + helper->blob_cab, + error); + if (helper->silo == NULL) return FALSE; - /* for each component in the store */ - apps = as_store_get_apps (store); + /* for each component in the silo */ + components = xb_silo_query (helper->silo, "component", 0, 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); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + 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++) { @@ -608,14 +612,14 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) g_autoptr(GError) error_local = NULL; /* is this component valid for the device */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (priv->engine, task, helper->flags, &error_local)) { g_debug ("requirement on %s:%s failed: %s", fu_device_get_id (device), - as_app_get_id (app), + xb_node_query_text (component, "id", NULL), error_local->message); g_ptr_array_add (errors, g_steal_pointer (&error_local)); continue; diff --git a/src/fu-plugin.h b/src/fu-plugin.h index 1375d9f9c..273777703 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -7,7 +7,6 @@ #ifndef __FU_PLUGIN_H #define __FU_PLUGIN_H -#include #include #include #include diff --git a/src/fu-self-test.c b/src/fu-self-test.c index be8c2c4f9..6674757cf 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -6,7 +6,7 @@ #include "config.h" -#include +#include #include #include #include @@ -45,24 +45,31 @@ static void fu_engine_requirements_missing_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsRequire) req = as_require_new (); + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " not.going.to.exist" + " " + ""; /* set up a dummy version */ fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); /* make the component require one thing */ - as_require_set_kind (req, AS_REQUIRE_KIND_ID); - as_require_set_compare (req, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req, "1.2.3"); - as_require_set_value (req, "not.going.to.exist"); - as_app_add_require (app, req); + 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 */ - task = fu_install_task_new (NULL, app); + task = fu_install_task_new (NULL, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -74,23 +81,31 @@ static void fu_engine_requirements_unsupported_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsRequire) req = as_require_new (); + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " " + " " + ""; /* set up a dummy version */ fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); /* make the component require one thing that we don't support */ - as_require_set_kind (req, AS_REQUIRE_KIND_LAST); - as_require_set_compare (req, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req, "2.6.0"); - as_app_add_require (app, req); + 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 */ - task = fu_install_task_new (NULL, app); + task = fu_install_task_new (NULL, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -102,25 +117,32 @@ static void fu_engine_requirements_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsRequire) req = as_require_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; + const gchar *xml = + "" + " " + " org.test.dummy" + " " + ""; /* set up some dummy versions */ fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); fu_engine_add_runtime_version (engine, "com.hughski.colorhug", "7.8.9"); /* make the component require one thing */ - as_require_set_kind (req, AS_REQUIRE_KIND_ID); - as_require_set_compare (req, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req, "1.2.3"); - as_require_set_value (req, "org.test.dummy"); - as_app_add_require (app, req); + 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 (NULL, app); + task = fu_install_task_new (NULL, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -132,17 +154,28 @@ static void fu_engine_requirements_device_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsChecksum) csum = as_checksum_new (); - g_autoptr(AsRequire) req1 = as_require_new (); - g_autoptr(AsRequire) req2 = as_require_new (); - g_autoptr(AsRequire) req3 = as_require_new (); - g_autoptr(AsProvide) prov = as_provide_new (); - g_autoptr(AsRelease) rel = as_release_new (); g_autoptr(FuDevice) device = 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; + const gchar *xml = + "" + " " + " " + " bootloader" + " vendor-id" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; /* set up a dummy device */ fu_device_set_version (device, "1.2.3"); @@ -152,35 +185,15 @@ fu_engine_requirements_device_func (void) fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); /* make the component require three things */ - as_require_set_kind (req1, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req1, AS_REQUIRE_COMPARE_GE); - as_require_set_version (req1, "1.2.3"); - as_app_add_require (app, req1); - as_require_set_kind (req2, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req2, AS_REQUIRE_COMPARE_EQ); - as_require_set_version (req2, "4.5.6"); - as_require_set_value (req2, "bootloader"); - as_app_add_require (app, req3); - as_require_set_kind (req3, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req3, AS_REQUIRE_COMPARE_EQ); - as_require_set_version (req3, "FFFF"); - as_require_set_value (req3, "vendor-id"); - as_app_add_require (app, req3); - - /* add release */ - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - as_checksum_set_filename (csum, "bios.bin"); - as_release_set_version (rel, "1.2.4"); - as_release_add_checksum (rel, csum); - as_app_add_release (app, rel); - - /* add GUID to match */ - as_provide_set_kind (prov, AS_PROVIDE_KIND_FIRMWARE_FLASHED); - as_provide_set_value (prov, "12345678-1234-1234-1234-123456789012"); - as_app_add_provide (app, prov); + 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 (device, app); + task = fu_install_task_new (device, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -192,16 +205,31 @@ static void fu_engine_requirements_other_device_func (void) { gboolean ret; - g_autoptr(AsApp) app = as_app_new (); - g_autoptr(AsChecksum) csum = as_checksum_new (); - g_autoptr(AsProvide) prov = as_provide_new (); - g_autoptr(AsRelease) rel = as_release_new (); - g_autoptr(AsRequire) req1 = as_require_new (); 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 = + "" + " " + " 00000000-0000-0000-0000-000000000000" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up a dummy device */ fu_device_set_version (device1, "1.2.3"); @@ -216,27 +244,16 @@ fu_engine_requirements_other_device_func (void) fu_device_add_guid (device2, "00000000-0000-0000-0000-000000000000"); fu_engine_add_device (engine, device2); - /* make the component require another device version */ - as_require_set_kind (req1, AS_REQUIRE_KIND_FIRMWARE); - as_require_set_compare (req1, AS_REQUIRE_COMPARE_GT); - as_require_set_version (req1, "4.0.0"); - as_require_set_value (req1, "00000000-0000-0000-0000-000000000000"); - as_app_add_require (app, req1); - - /* add release */ - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - as_checksum_set_filename (csum, "bios.bin"); - as_release_set_version (rel, "1.2.4"); - as_release_add_checksum (rel, csum); - as_app_add_release (app, rel); - - /* add GUID to match */ - as_provide_set_kind (prov, AS_PROVIDE_KIND_FIRMWARE_FLASHED); - as_provide_set_value (prov, "12345678-1234-1234-1234-123456789012"); - as_app_add_provide (app, prov); + /* 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 (device1, app); + task = fu_install_task_new (device1, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -253,6 +270,10 @@ fu_engine_device_priority_func (void) g_autoptr(FuDevice) device = NULL; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(GError) error = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* add low prio then high then low */ fu_device_set_id (device1, "id1"); @@ -296,6 +317,10 @@ fu_engine_device_parent_func (void) g_autoptr(FuDevice) device2 = fu_device_new (); g_autoptr(FuDevice) device3 = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* add child */ fu_device_set_id (device1, "child"); @@ -340,6 +365,10 @@ fu_engine_partial_hash_func (void) g_autoptr(GError) error = NULL; g_autoptr(GError) error_none = NULL; g_autoptr(GError) error_both = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ fu_plugin_set_name (plugin, "test"); @@ -396,6 +425,10 @@ fu_engine_device_unlock_func (void) g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; /* load engine to get FuConfig set up */ ret = fu_engine_load (engine, &error); @@ -405,9 +438,17 @@ fu_engine_device_unlock_func (void) /* add the hardcoded 'fwupd' metadata */ filename = fu_test_get_filename (TESTDATADIR, "metadata.xml"); g_assert (filename != NULL); - ret = fu_engine_load_metadata_from_file (engine, filename, NULL, &error); + file = g_file_new_for_path (filename); + ret = xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, &error); g_assert_no_error (error); g_assert_true (ret); + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + fu_engine_set_silo (engine, silo); /* add a dummy device */ fu_device_set_id (device, "UEFI-dummy-dev0"); @@ -422,15 +463,16 @@ fu_engine_device_unlock_func (void) static void fu_engine_require_hwid_func (void) { - AsApp *app; gboolean ret; g_autofree gchar *filename = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuInstallTask) task = NULL; 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; #if !defined(HAVE_GCAB_0_8) && defined(__s390x__) /* See https://github.com/hughsie/fwupd/issues/318 for more information */ @@ -438,6 +480,9 @@ fu_engine_require_hwid_func (void) return; #endif + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + /* load engine to get FuConfig set up */ ret = fu_engine_load (engine, &error); g_assert_no_error (error); @@ -449,9 +494,9 @@ fu_engine_require_hwid_func (void) blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* add a dummy device */ fu_device_set_id (device, "test_device"); @@ -460,12 +505,13 @@ fu_engine_require_hwid_func (void) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_engine_add_device (engine, device); - /* get app */ - app = as_store_get_app_by_id (store, "com.hughski.test.firmware"); - g_assert_nonnull (app); + /* get component */ + component = xb_silo_query_first (silo, "component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* check requirements */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); ret = fu_engine_check_requirements (engine, task, FWUPD_INSTALL_FLAG_NONE, &error); @@ -491,6 +537,10 @@ fu_engine_downgrade_func (void) g_autoptr(GPtrArray) releases = NULL; g_autoptr(GPtrArray) releases_up = NULL; g_autoptr(GPtrArray) remotes = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* write a broken file */ ret = g_file_set_contents ("/tmp/fwupd-self-test/broken.xml.gz", @@ -558,10 +608,6 @@ fu_engine_downgrade_func (void) g_assert_no_error (error); g_assert (ret); - /* expect just one broken remote to fail */ - g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, - "failed to load remote broken: *"); - testdatadir = fu_test_get_filename (TESTDATADIR, "."); g_assert (testdatadir != NULL); g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); @@ -627,25 +673,32 @@ fu_engine_downgrade_func (void) static void fu_engine_history_func (void) { - AsApp *app; gboolean ret; + g_autofree gchar *checksum = NULL; g_autofree gchar *device_str_expected = NULL; g_autofree gchar *device_str = NULL; g_autofree gchar *filename = NULL; - g_autofree gchar *checksum = NULL; g_autofree gchar *testdatadir = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device2 = NULL; - g_autoptr(FwupdDevice) device3 = NULL; - g_autoptr(FwupdDevice) device4 = NULL; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuHistory) history = NULL; g_autoptr(FuInstallTask) task = NULL; g_autoptr(FuPlugin) plugin = fu_plugin_new (); + g_autoptr(FwupdDevice) device3 = NULL; + g_autoptr(FwupdDevice) device4 = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* ensure the history database is fresh */ + g_unlink ("/tmp/fwupd-self-test/var/lib/fwupd/pending.db"); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); @@ -681,16 +734,17 @@ fu_engine_history_func (void) blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); - /* get app */ - app = as_store_get_app_by_id (store, "com.hughski.test.firmware"); - g_assert_nonnull (app); + /* get component */ + component = xb_silo_query_first (silo, "component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); /* install it */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); ret = fu_engine_install (engine, task, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); @@ -749,14 +803,12 @@ fu_engine_history_func (void) static void fu_engine_history_error_func (void) { - AsApp *app; gboolean ret; + g_autofree gchar *checksum = NULL; g_autofree gchar *device_str_expected = NULL; g_autofree gchar *device_str = NULL; g_autofree gchar *filename = NULL; - g_autofree gchar *checksum = NULL; g_autofree gchar *testdatadir = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device2 = NULL; g_autoptr(FuDevice) device = fu_device_new (); g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); @@ -767,6 +819,12 @@ fu_engine_history_error_func (void) g_autoptr(GError) error2 = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ g_setenv ("FWUPD_PLUGIN_TEST", "fail", TRUE); @@ -804,12 +862,13 @@ fu_engine_history_error_func (void) blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); - app = as_store_get_app_by_id (store, "com.hughski.test.firmware"); - g_assert_nonnull (app); - task = fu_install_task_new (device, app); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component/id[text()='com.hughski.test.firmware']/..", &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, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); @@ -2281,13 +2340,17 @@ fu_plugin_composite_func (void) { GError *error = NULL; gboolean ret; - GPtrArray *apps; g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuPlugin) plugin = fu_plugin_new (); - g_autoptr(GPtrArray) devices = NULL; g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* create CAB file */ blob = _build_cab (GCAB_COMPRESSION_NONE, @@ -2310,6 +2373,9 @@ fu_plugin_composite_func (void) " \n" " \n" " \n" + " \n" + " plain\n" + " \n" "", "acme.module2.metainfo.xml", "\n" @@ -2320,6 +2386,9 @@ fu_plugin_composite_func (void) " \n" " \n" " \n" + " \n" + " plain\n" + " \n" "", "firmware.bin", "world", NULL); @@ -2327,11 +2396,13 @@ fu_plugin_composite_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert_nonnull (store); - apps = as_store_get_apps (store); - g_assert_cmpint (apps->len, ==, 3); + g_assert_nonnull (silo); + components = xb_silo_query (silo, "component", 0, &error); + g_assert_no_error (error); + g_assert_nonnull (components); + g_assert_cmpint (components->len, ==, 3); /* set up dummy plugin */ g_setenv ("FWUPD_PLUGIN_TEST", "composite", TRUE); @@ -2372,8 +2443,8 @@ fu_plugin_composite_func (void) } /* produce install tasks */ - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + 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->len; j++) { @@ -2382,14 +2453,14 @@ fu_plugin_composite_func (void) g_autoptr(GError) error_local = NULL; /* is this component valid for the device */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (engine, task, 0, &error_local)) { g_debug ("requirement on %s:%s failed: %s", fu_device_get_id (device), - as_app_get_id (app), + xb_node_query_text (component, "id", NULL), error_local->message); continue; } @@ -2434,16 +2505,16 @@ fu_plugin_composite_func (void) static void fu_common_store_cab_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; - AsRequire *req; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbNode) req = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "acme.metainfo.xml", "\n" @@ -2454,9 +2525,8 @@ fu_common_store_cab_func (void) " \n" " \n" " \n" - " \n" " 5\n" - " 7c211433f02071597741e6ff5a8ea34789abbf43\n" + " 7c211433f02071597741e6ff5a8ea34789abbf43\n" "

We fixed things

\n" "
\n" "
\n" @@ -2471,38 +2541,42 @@ fu_common_store_cab_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.dfu"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + csum = xb_node_query_first (rel, "checksum[@target='content']", &error); + g_assert_nonnull (csum); + g_assert_cmpstr (xb_node_get_text (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu)"); g_assert_nonnull (blob_tmp); - blob_tmp = as_release_get_blob (rel, "firmware.dfu.asc"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu.asc)"); g_assert_nonnull (blob_tmp); - req = as_app_get_require_by_value (app, AS_REQUIRE_KIND_ID, "org.freedesktop.fwupd"); + req = xb_node_query_first (component, "requires/id", &error); + g_assert_no_error (error); g_assert_nonnull (req); } static void fu_common_store_cab_unsigned_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "acme.metainfo.xml", "\n" @@ -2517,36 +2591,37 @@ fu_common_store_cab_unsigned_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.bin"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + csum = xb_node_query_first (rel, "checksum[@target='content']", &error); + g_assert_null (csum); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); g_assert_nonnull (blob_tmp); - blob_tmp = as_release_get_blob (rel, "firmware.bin.asc"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin.asc)"); g_assert_null (blob_tmp); } static void fu_common_store_cab_folder_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "lvfs\\acme.metainfo.xml", "\n" @@ -2561,26 +2636,26 @@ fu_common_store_cab_folder_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.bin"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); g_assert_nonnull (blob_tmp); } static void fu_common_store_cab_error_no_metadata_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2592,15 +2667,15 @@ fu_common_store_cab_error_no_metadata_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_wrong_size_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2621,15 +2696,15 @@ fu_common_store_cab_error_wrong_size_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_missing_file_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2649,15 +2724,15 @@ fu_common_store_cab_error_missing_file_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_size_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2675,15 +2750,15 @@ fu_common_store_cab_error_size_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 123, &error); + silo = fu_common_cab_build_silo (blob, 123, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_wrong_checksum_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -2703,9 +2778,9 @@ fu_common_store_cab_error_wrong_checksum_func (void) g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static gboolean diff --git a/src/fu-tool.c b/src/fu-tool.c index 5cfa65b54..858c90311 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -649,13 +649,13 @@ fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GErro static gboolean fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) { - GPtrArray *apps; g_autofree gchar *filename = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob_cab = NULL; + g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) devices_possible = NULL; g_autoptr(GPtrArray) errors = NULL; g_autoptr(GPtrArray) install_tasks = NULL; + g_autoptr(XbSilo) silo = NULL; /* load engine */ if (!fu_util_start_engine (priv, error)) @@ -687,22 +687,24 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) if (filename == NULL) return FALSE; - /* parse store */ + /* parse silo */ blob_cab = fu_common_get_contents_bytes (filename, error); if (blob_cab == NULL) { fu_util_maybe_prefix_sandbox_error (filename, error); return FALSE; } - store = fu_engine_get_store_from_blob (priv->engine, blob_cab, error); - if (store == NULL) + silo = fu_engine_get_silo_from_blob (priv->engine, blob_cab, error); + if (silo == NULL) + return FALSE; + components = xb_silo_query (silo, "component", 0, error); + if (components == NULL) return FALSE; - apps = as_store_get_apps (store); - /* for each component in the store */ + /* 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); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + 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++) { @@ -711,13 +713,13 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) g_autoptr(GError) error_local = NULL; /* is this component valid for the device */ - task = fu_install_task_new (device, app); + task = fu_install_task_new (device, component); if (!fu_engine_check_requirements (priv->engine, task, priv->flags, &error_local)) { g_debug ("requirement on %s:%s failed: %s", fu_device_get_id (device), - as_app_get_id (app), + xb_node_query_text (component, "id", NULL), error_local->message); g_ptr_array_add (errors, g_steal_pointer (&error_local)); continue; diff --git a/src/fu-util.c b/src/fu-util.c index 3ffa68b13..147e430b3 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -9,7 +9,7 @@ #include "config.h" #include -#include +#include #include #include #include @@ -435,6 +435,60 @@ fu_util_perhaps_show_unreported (FuUtilPrivate *priv, GError **error) return fu_util_report_history (priv, NULL, error); } +static gchar * +fu_util_convert_appstream_description (const gchar *xml, GError **error) +{ + g_autoptr(GString) str = g_string_new (NULL); + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + + /* parse XML */ + silo = xb_silo_new_from_xml (xml, error); + if (silo == NULL) + return NULL; + + n = xb_silo_get_root (silo); + while (n != NULL) { + g_autoptr(XbNode) n2 = NULL; + + /* support

,

    ,
      and
    1. , ignore all else */ + if (g_strcmp0 (xb_node_get_element (n), "p") == 0) { + g_string_append_printf (str, "%s\n\n", xb_node_get_text (n)); + } else if (g_strcmp0 (xb_node_get_element (n), "ul") == 0) { + g_autoptr(GPtrArray) children = xb_node_get_children (n); + for (guint i = 0; i < children->len; i++) { + XbNode *nc = g_ptr_array_index (children, i); + if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { + g_string_append_printf (str, " • %s\n", + xb_node_get_text (nc)); + } + } + g_string_append (str, "\n"); + } else if (g_strcmp0 (xb_node_get_element (n), "ol") == 0) { + g_autoptr(GPtrArray) children = xb_node_get_children (n); + for (guint i = 0; i < children->len; i++) { + XbNode *nc = g_ptr_array_index (children, i); + if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { + g_string_append_printf (str, " %u. %s\n", + i + 1, + xb_node_get_text (nc)); + } + } + g_string_append (str, "\n"); + } + + n2 = xb_node_get_next (n); + g_set_object (&n, n2); + } + + /* remove extra newline */ + if (str->len > 0) + g_string_truncate (str, str->len - 1); + + /* success */ + return g_string_free (g_steal_pointer (&str), FALSE); +} + static gboolean fu_util_modify_remote_warning (FuUtilPrivate *priv, FwupdRemote *remote, GError **error) { @@ -445,7 +499,7 @@ fu_util_modify_remote_warning (FuUtilPrivate *priv, FwupdRemote *remote, GError warning_markup = fwupd_remote_get_agreement (remote); if (warning_markup == NULL) return TRUE; - warning_plain = as_markup_convert_simple (warning_markup, error); + warning_plain = fu_util_convert_appstream_description (warning_markup, error); if (warning_plain == NULL) return FALSE; @@ -1480,7 +1534,7 @@ fu_util_get_releases (FuUtilPrivate *priv, gchar **values, GError **error) tmp = fwupd_release_get_description (rel); if (tmp != NULL) { g_autofree gchar *desc = NULL; - desc = as_markup_convert_simple (tmp, NULL); + desc = fu_util_convert_appstream_description (tmp, NULL); /* TRANSLATORS: section header for firmware description */ fu_util_print_data (_("Description"), desc); } @@ -1727,9 +1781,7 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) tmp = fwupd_release_get_description (rel); if (tmp != NULL) { g_autofree gchar *md = NULL; - md = as_markup_convert (tmp, - AS_MARKUP_CONVERT_FORMAT_SIMPLE, - NULL); + md = fu_util_convert_appstream_description (tmp, NULL); if (md != NULL) { /* TRANSLATORS: section header for long firmware desc */ fu_util_print_data (_("Update Description"), md); diff --git a/src/meson.build b/src/meson.build index b4b816444..ed49f039d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -47,13 +47,13 @@ libfwupdprivate = static_library( include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, giounix, gudev, gusb, soup, sqlite, libarchive, + libxmlb, valgrind, uuid, ], @@ -74,7 +74,7 @@ fwupdmgr = executable( include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, gudev, gusb, @@ -140,7 +140,7 @@ fwupdtool = executable( ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, @@ -220,7 +220,7 @@ executable( ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, @@ -290,7 +290,7 @@ if get_option('tests') ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, @@ -350,7 +350,7 @@ if get_option('introspection') include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, gir_dep, giounix, gusb, diff --git a/subprojects/.gitignore b/subprojects/.gitignore new file mode 100644 index 000000000..d8d6c81a5 --- /dev/null +++ b/subprojects/.gitignore @@ -0,0 +1 @@ +libxmlb diff --git a/subprojects/libxmlb.wrap b/subprojects/libxmlb.wrap new file mode 100644 index 000000000..bcf554748 --- /dev/null +++ b/subprojects/libxmlb.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory = libxmlb +url = https://github.com/hughsie/libxmlb.git +revision = wip/subproject From 7fb61fdd1cf5f50ad8a7b76a8aff36ab0e2d60f2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 11 Oct 2018 20:26:24 +0100 Subject: [PATCH 028/254] Support the Intel ME version format This slightly weird encoding is going to be used by Lenovo for firmware updates. It will also be used to quirk the ME UEFI device added from the ESRT. --- src/fu-common-version.c | 12 ++++++++++++ src/fu-common-version.h | 2 ++ src/fu-self-test.c | 2 ++ 3 files changed, 16 insertions(+) diff --git a/src/fu-common-version.c b/src/fu-common-version.c index 5088cfc31..d86fe5698 100644 --- a/src/fu-common-version.c +++ b/src/fu-common-version.c @@ -37,6 +37,8 @@ fu_common_version_format_from_string (const gchar *str) return FU_VERSION_FORMAT_BCD; if (g_strcmp0 (str, "plain") == 0) return FU_VERSION_FORMAT_PLAIN; + if (g_strcmp0 (str, "intel-me") == 0) + return FU_VERSION_FORMAT_INTEL_ME; return FU_VERSION_FORMAT_QUAD; } @@ -61,6 +63,8 @@ fu_common_version_format_to_string (FuVersionFormat kind) return "bcd"; if (kind == FU_VERSION_FORMAT_PLAIN) return "plain"; + if (kind == FU_VERSION_FORMAT_INTEL_ME) + return "intel-me"; return NULL; } @@ -111,6 +115,14 @@ fu_common_version_from_uint32 (guint32 val, FuVersionFormat kind) FU_COMMON_VERSION_DECODE_BCD(val >> 8), FU_COMMON_VERSION_DECODE_BCD(val)); } + if (kind == FU_VERSION_FORMAT_INTEL_ME) { + /* aaa+11.bbbbb.cccccccc.dddddddddddddddd */ + return g_strdup_printf ("%u.%u.%u.%u", + ((val >> 29) & 0x07) + 0x0b, + (val >> 24) & 0x1f, + (val >> 16) & 0xff, + val & 0xffff); + } return NULL; } diff --git a/src/fu-common-version.h b/src/fu-common-version.h index 059fc4d83..13cfe4040 100644 --- a/src/fu-common-version.h +++ b/src/fu-common-version.h @@ -17,6 +17,7 @@ * @FU_VERSION_FORMAT_TRIPLET: Use Microsoft-style AA.BB.CCDD version numbers * @FU_VERSION_FORMAT_PAIR: Use two AABB.CCDD version numbers * @FU_VERSION_FORMAT_BCD: Use binary coded decimal notation + * @FU_VERSION_FORMAT_INTEL_ME: Use Intel ME-style notation * * The flags used when parsing version numbers. **/ @@ -27,6 +28,7 @@ typedef enum { FU_VERSION_FORMAT_TRIPLET, /* Since: 1.2.0 */ FU_VERSION_FORMAT_PAIR, /* Since: 1.2.0 */ FU_VERSION_FORMAT_BCD, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_INTEL_ME, /* Since: 1.2.0 */ /*< private >*/ FU_VERSION_FORMAT_LAST } FuVersionFormat; diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 6674757cf..faee350f8 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -2959,6 +2959,8 @@ fu_common_version_func (void) { 0xff000100, "255.0.256", FU_VERSION_FORMAT_TRIPLET }, { 0x0, "0", FU_VERSION_FORMAT_PLAIN }, { 0xff000100, "4278190336", FU_VERSION_FORMAT_PLAIN }, + { 0x0, "11.0.0.0", FU_VERSION_FORMAT_INTEL_ME }, + { 0xffffffff, "18.31.255.65535", FU_VERSION_FORMAT_INTEL_ME }, { 0, NULL } }; struct { From 2ef4e09e885599b095d1546820a828a6f143ac3d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Oct 2018 20:55:06 -0500 Subject: [PATCH 029/254] dell-dock: Add missing unlock call for MST via dell_dock plugin When automatic relock was put in place this caused a problem that some situations the device won't be in the right state when calling update. --- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index 5897b16b1..21887fb3f 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -787,6 +787,10 @@ fu_dell_dock_mst_write_fw (FuDevice *device, self->relock_id = 0; } + /* power up controller in case it's asleep */ + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + dynamic_version = g_strdup_printf ("%02x.%02x.%02x", data[self->blob_major_offset], data[self->blob_minor_offset], From ce4a1a8ba638c4fc44a1d14401b5a2731d002fd1 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Oct 2018 22:33:58 -0500 Subject: [PATCH 030/254] dell_dock: Use correct offset for finding version of MST (Fixes: #804) The offset that was previously used was dependent upon compiler behavior. This address is fixed and won't change between versions. --- plugins/dell-dock/dell-dock.quirk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk index 345eb30ab..5ec659f5d 100644 --- a/plugins/dell-dock/dell-dock.quirk +++ b/plugins/dell-dock/dell-dock.quirk @@ -100,9 +100,9 @@ FirmwareSizeMax=524288 DellDockUnlockTarget = 9 InstallDuration = 95 DellDockInstallDurationI2C=360 -DellDockBlobMajorOffset = 0x06F0 -DellDockBlobMinorOffset = 0x06F1 -DellDockBlobBuildOffset = 0x06F2 +DellDockBlobMajorOffset = 0x18400 +DellDockBlobMinorOffset = 0x18401 +DellDockBlobBuildOffset = 0x18402 # Thunderbolt controller [Guid=TBT-00d4b070] From 89ab873f721d98c879b4abba6ce593a17828d080 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 18 Oct 2018 11:34:22 +0100 Subject: [PATCH 031/254] trivial: Add yet another version encoding This variant is a quad-style, but with the Microsoft style 4 digit BuildVer. --- docs/version-format.md | 58 +++++++++++++++++++++++++++++++++++++++++ src/fu-common-version.c | 12 +++++++++ src/fu-common-version.h | 4 ++- src/fu-self-test.c | 2 ++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 docs/version-format.md diff --git a/docs/version-format.md b/docs/version-format.md new file mode 100644 index 000000000..40b3a8464 --- /dev/null +++ b/docs/version-format.md @@ -0,0 +1,58 @@ +Version Formats +=============== + +In some circumstances fwupd has to convert from a unsigned integer version +number into something that has either been used in documentation or has been +defined in some specification. +A good example here is the UEFI ESRT table, which specifies a `uint32_t` for +the version but does not specify how this should be formatted for the user. + +As is typical in underspecified specifications, vendors have converted the +integer in different ways. For instance, Dell uses version strings like 1.2.3 +and Microsoft use versions like 1.2.3.4. + +The fwudp daemon can match specific devices and apply the correct version style +using quirk files. The version format can also be specified in the firmware +`metainfo.xml` file so that the new version is correctly shown, and so that it +matches on the LVFS website. + +The current version formats supported by fwupd and the LVFS are: + + * `plain`: Use plain integer version numbers with no dots, e.g. `AABBCCDD` + * `quad`: Use Dell-style `AA.BB.CC.DD` version numbers + * `triplet`: Use Microsoft-style `AA.BB.CCDD` version numbers + * `pair`: Use two `AABB.CCDD` version numbers + * `bcd`: Use binary coded decimal notation + * `intel-me`: Use Intel ME-style notation (`aaa+11.bbbbb.CC.DDDD`) + * `intel-me2`: Use alternate Intel ME-style-style `A.B.CC.DDDD` notation + +These can be specified in quirk files like this: + + # Vendor Modelname + [Guid=5b92717b-2cad-4a96-a13b-9d65781df8bf] + VersionFormat = intel-me2 + +...or in metainfo.xml files like this: + + + intel-me2 + + +Runtime requirements +-------------------- + +Versions of fwupd `< 1.2.0` can only support firmware updates with key values +`LVFS::VersionFormat` of `quad` and `triplet`. Additionally, on older versions +no quirk `VersionFormat` device fixups are supported. + +If want to use one of the additional version formats you should depend on a +specific version of fwupd in the firmware file: + + + org.freedesktop.fwupd + + +This is not *strictly* required, as the integer value can be used for update +calculations if the version is specified in hex (e.g. `0x12345678`) in the +`` tag, although the user might get a bit confused if the update +version does not match the update description. diff --git a/src/fu-common-version.c b/src/fu-common-version.c index d86fe5698..bc98c2784 100644 --- a/src/fu-common-version.c +++ b/src/fu-common-version.c @@ -33,6 +33,8 @@ fu_common_version_format_from_string (const gchar *str) return FU_VERSION_FORMAT_TRIPLET; if (g_strcmp0 (str, "quad") == 0) return FU_VERSION_FORMAT_QUAD; + if (g_strcmp0 (str, "intel-me2") == 0) + return FU_VERSION_FORMAT_INTEL_ME2; if (g_strcmp0 (str, "bcd") == 0) return FU_VERSION_FORMAT_BCD; if (g_strcmp0 (str, "plain") == 0) @@ -59,6 +61,8 @@ fu_common_version_format_to_string (FuVersionFormat kind) return "triplet"; if (kind == FU_VERSION_FORMAT_QUAD) return "quad"; + if (kind == FU_VERSION_FORMAT_INTEL_ME2) + return "intel-me2"; if (kind == FU_VERSION_FORMAT_BCD) return "bcd"; if (kind == FU_VERSION_FORMAT_PLAIN) @@ -123,6 +127,14 @@ fu_common_version_from_uint32 (guint32 val, FuVersionFormat kind) (val >> 16) & 0xff, val & 0xffff); } + if (kind == FU_VERSION_FORMAT_INTEL_ME2) { + /* A.B.CC.DDDD */ + return g_strdup_printf ("%u.%u.%u.%u", + (val >> 28) & 0x0f, + (val >> 24) & 0x0f, + (val >> 16) & 0xff, + val & 0xffff); + } return NULL; } diff --git a/src/fu-common-version.h b/src/fu-common-version.h index 13cfe4040..8bcbcd059 100644 --- a/src/fu-common-version.h +++ b/src/fu-common-version.h @@ -17,7 +17,8 @@ * @FU_VERSION_FORMAT_TRIPLET: Use Microsoft-style AA.BB.CCDD version numbers * @FU_VERSION_FORMAT_PAIR: Use two AABB.CCDD version numbers * @FU_VERSION_FORMAT_BCD: Use binary coded decimal notation - * @FU_VERSION_FORMAT_INTEL_ME: Use Intel ME-style notation + * @FU_VERSION_FORMAT_INTEL_ME: Use Intel ME-style bitshifted notation + * @FU_VERSION_FORMAT_INTEL_ME2: Use Intel ME-style A.B.CC.DDDD notation notation * * The flags used when parsing version numbers. **/ @@ -29,6 +30,7 @@ typedef enum { FU_VERSION_FORMAT_PAIR, /* Since: 1.2.0 */ FU_VERSION_FORMAT_BCD, /* Since: 1.2.0 */ FU_VERSION_FORMAT_INTEL_ME, /* Since: 1.2.0 */ + FU_VERSION_FORMAT_INTEL_ME2, /* Since: 1.2.0 */ /*< private >*/ FU_VERSION_FORMAT_LAST } FuVersionFormat; diff --git a/src/fu-self-test.c b/src/fu-self-test.c index faee350f8..3c774b558 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -2961,6 +2961,8 @@ fu_common_version_func (void) { 0xff000100, "4278190336", FU_VERSION_FORMAT_PLAIN }, { 0x0, "11.0.0.0", FU_VERSION_FORMAT_INTEL_ME }, { 0xffffffff, "18.31.255.65535", FU_VERSION_FORMAT_INTEL_ME }, + { 0x0b32057a, "11.11.50.1402", FU_VERSION_FORMAT_INTEL_ME }, + { 0xb8320d84, "11.8.50.3460", FU_VERSION_FORMAT_INTEL_ME2 }, { 0, NULL } }; struct { From ce712426f81b40d92b305cbabef4a822ad54d354 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 18 Oct 2018 14:56:24 +0100 Subject: [PATCH 032/254] uefi: Set the quirks on created devices Ensure the quirk object is set, and then add the GUIDs first so that the version format can be set from a quirk file. Additionally, only overwrite the fallback name if the name has not already been set manually from a quirk. --- plugins/uefi/fu-plugin-uefi.c | 41 ++++++----------- plugins/uefi/fu-uefi-device.c | 83 ++++++++++++++++++++++++----------- 2 files changed, 71 insertions(+), 53 deletions(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 59de81ac5..c9ec9cf6e 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -477,36 +477,22 @@ fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **er { FuUefiDeviceKind device_kind; FuVersionFormat version_format; - guint32 version_raw; - g_autofree gchar *name = NULL; - g_autofree gchar *version_lowest = NULL; - g_autofree gchar *version = NULL; - /* add details to the device */ + /* set default version format */ device_kind = fu_uefi_device_get_kind (dev); version_format = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind); - version_raw = fu_uefi_device_get_version (dev); - version = fu_common_version_from_uint32 (version_raw, version_format); - fu_device_set_version (dev, version); - name = fu_plugin_uefi_get_name_for_type (plugin, fu_uefi_device_get_kind (dev)); - if (name != NULL) - fu_device_set_name (FU_DEVICE (dev), name); - version_raw = fu_uefi_device_get_version_lowest (dev); - if (version_raw != 0) { - version_lowest = fu_common_version_from_uint32 (version_raw, - version_format); - fu_device_set_version_lowest (FU_DEVICE (dev), version_lowest); - } - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_REQUIRE_AC); - if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { - /* nothing better in the icon naming spec */ - fu_device_add_icon (FU_DEVICE (dev), "audio-card"); - } else { - /* this is probably system firmware */ - fu_device_add_icon (FU_DEVICE (dev), "computer"); - fu_device_add_guid (FU_DEVICE (dev), "main-system-firmware"); + fu_device_set_version_format (FU_DEVICE (dev), version_format); + + /* probe to get add GUIDs (and hence any quirk fixups) */ + if (!fu_device_probe (FU_DEVICE (dev), error)) + return FALSE; + + /* set fallback name if nothing else is set */ + if (fu_device_get_name (FU_DEVICE (dev)) == 0) { + g_autofree gchar *name = NULL; + name = fu_plugin_uefi_get_name_for_type (plugin, fu_uefi_device_get_kind (dev)); + if (name != NULL) + fu_device_set_name (FU_DEVICE (dev), name); } /* success */ @@ -741,6 +727,7 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path); + fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) return FALSE; if (error_esp != NULL) { diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 64c314158..8073c2df9 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -367,6 +367,61 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) return TRUE; } +static gboolean +fu_uefi_device_probe (FuDevice *device, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + FuVersionFormat version_format; + g_autofree gchar *guid_devid = NULL; + g_autofree gchar *guid_strup = NULL; + g_autofree gchar *version_lowest = NULL; + g_autofree gchar *version = NULL; + + /* broken sysfs? */ + if (self->fw_class == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to read fw_class"); + return FALSE; + } + + /* add GUID first, as quirks may set the version format */ + fu_device_add_guid (device, self->fw_class); + + /* set versions */ + version_format = fu_device_get_version_format (device); + version = fu_common_version_from_uint32 (self->fw_version, version_format); + fu_device_set_version (device, version); + if (self->fw_version_lowest != 0) { + version_lowest = fu_common_version_from_uint32 (self->fw_version_lowest, + version_format); + fu_device_set_version_lowest (device, version_lowest); + } + + /* set flags */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC); + + /* add icons */ + if (self->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { + /* nothing better in the icon naming spec */ + fu_device_add_icon (device, "audio-card"); + } else { + /* this is probably system firmware */ + fu_device_add_icon (device, "computer"); + fu_device_add_guid (device, "main-system-firmware"); + } + + /* Windows seems to be case insensitive, but for convenience we'll + * match the upper case values typically specified in the .inf file */ + guid_strup = g_ascii_strup (self->fw_class, -1); + guid_devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup); + fu_device_add_guid (device, guid_devid); + return TRUE; +} + static void fu_uefi_device_init (FuUefiDevice *self) { @@ -389,26 +444,10 @@ fu_uefi_device_class_init (FuUefiDeviceClass *klass) FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); object_class->finalize = fu_uefi_device_finalize; klass_device->to_string = fu_uefi_device_to_string; + klass_device->probe = fu_uefi_device_probe; klass_device->write_firmware = fu_uefi_device_write_firmware; } -static void -fu_uefi_device_add_win10_guid (FuUefiDevice *self) -{ - g_autofree gchar *guid_devid = NULL; - g_autofree gchar *guid_strup = NULL; - - /* broken sysfs? */ - if (self->fw_class == NULL) - return; - - /* windows seems to be case insensitive, but for convenience we'll - * match the upper case values typically specified in the .inf file */ - guid_strup = g_ascii_strup (self->fw_class, -1); - guid_devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup); - fu_device_add_guid (FU_DEVICE (self), guid_devid); -} - FuUefiDevice * fu_uefi_device_new_from_entry (const gchar *entry_path) { @@ -423,10 +462,8 @@ fu_uefi_device_new_from_entry (const gchar *entry_path) /* read values from sysfs */ fw_class_fn = g_build_filename (entry_path, "fw_class", NULL); - if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) { + if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) g_strdelimit (self->fw_class, "\n", '\0'); - fu_device_add_guid (FU_DEVICE (self), self->fw_class); - } self->capsule_flags = fu_uefi_read_file_as_uint64 (entry_path, "capsule_flags"); self->kind = fu_uefi_read_file_as_uint64 (entry_path, "fw_type"); self->fw_version = fu_uefi_read_file_as_uint64 (entry_path, "fw_version"); @@ -444,9 +481,6 @@ fu_uefi_device_new_from_entry (const gchar *entry_path) self->fw_class, self->fmp_hardware_instance); fu_device_set_id (FU_DEVICE (self), id); - /* this is the DeviceID used in Windows 10 */ - fu_uefi_device_add_win10_guid (self); - return self; } @@ -467,9 +501,6 @@ fu_uefi_device_new_from_dev (FuDevice *dev) self->capsule_flags = 0; /* FIXME? */ self->fw_version = 0; /* FIXME? */ g_assert (self->fw_class != NULL); - - /* this is the DeviceID used in Windows 10 */ - fu_uefi_device_add_win10_guid (self); return self; } From 74fe343213f8b190cc324722617fa765e5582ac8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 18 Oct 2018 11:41:56 +0100 Subject: [PATCH 033/254] Add version format quirks for several Lenovo machines --- plugins/uefi/meson.build | 4 ++++ plugins/uefi/uefi.quirk | 14 ++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 plugins/uefi/uefi.quirk diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index 098af7991..c037e1b30 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -3,6 +3,10 @@ subdir('efi') cargs = ['-DG_LOG_DOMAIN="FuPluginUefi"'] cargs += '-DEFI_APP_LOCATION_BUILD="' + app.full_path() + '"' +install_data(['uefi.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_uefi', sources : [ 'fu-plugin-uefi.c', diff --git a/plugins/uefi/uefi.quirk b/plugins/uefi/uefi.quirk new file mode 100644 index 000000000..a9719fef8 --- /dev/null +++ b/plugins/uefi/uefi.quirk @@ -0,0 +1,14 @@ +# Lenovo ThinkStation P920/P720 +[Guid=cc850e7a-6713-4fe3-8144-321a9e485ae0] +VersionFormat = intel-me +Name = Intel Management Engine + +# Lenovo ThinkStation P520/P520c +[Guid=e3af51e5-5afb-4b48-b5cb-13bf26becaab] +VersionFormat = intel-me +Name = Intel Management Engine + +# Lenovo ThinkStation P330/P330 Tiny & ThinkCentre M920X/M920q +[Guid=5b92717b-2cad-4a96-a13b-9d65781df8bf] +VersionFormat = intel-me2 +Name = Intel Management Engine From cdcd6a2423b2b7100c593c68c7b03dac7ffa33f0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 18 Oct 2018 16:13:28 +0100 Subject: [PATCH 034/254] trivial: Add VersionFormat to the fu_device_to_string() output --- src/fu-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fu-device.c b/src/fu-device.c index b03dbfb9a..e998fdf95 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -1477,6 +1477,10 @@ fu_device_to_string (FuDevice *self) tmp = fwupd_device_to_string (FWUPD_DEVICE (self)); if (tmp != NULL && tmp[0] != '\0') g_string_append (str, tmp); + if (priv->version_format != FU_VERSION_FORMAT_UNKNOWN) { + fwupd_pad_kv_str (str, "VersionFormat", + fu_common_version_format_to_string (priv->version_format)); + } if (priv->alternate_id != NULL) fwupd_pad_kv_str (str, "AlternateId", priv->alternate_id); if (priv->equivalent_id != NULL) From f6d01b16deab8c1cc15b0f152fb614c4e1e62cce Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 18 Oct 2018 12:57:10 -0500 Subject: [PATCH 035/254] fwupdmgr/fwupdtool: Move firmware builder from fwupdmgr to fwupdtool This command is really a power user command and should live in fwupdtool with similar debugging and development features. --- data/bash-completion/fwupdmgr | 18 ----------------- data/bash-completion/fwupdtool.in | 18 +++++++++++++++++ src/fu-tool.c | 33 +++++++++++++++++++++++++++++++ src/fu-util.c | 33 ------------------------------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/data/bash-completion/fwupdmgr b/data/bash-completion/fwupdmgr index 2e27dadb0..495556a47 100644 --- a/data/bash-completion/fwupdmgr +++ b/data/bash-completion/fwupdmgr @@ -1,5 +1,4 @@ _fwupdmgr_cmd_list=( - 'build-firmware' 'clear-history' 'clear-offline' 'clear-results' @@ -147,23 +146,6 @@ _fwupdmgr() _show_modifiers fi ;; - build-firmware) - #file in - if [[ "$prev" = "$command" ]]; then - _filedir - #file out - elif [[ "$prev" = "${COMP_WORDS[2]}" ]]; then - _filedir - #script - elif [[ "$prev" = "${COMP_WORDS[3]}" ]]; then - _filedir - #output - elif [[ "$prev" = "${COMP_WORDS[4]}" ]]; then - _filedir - else - _show_modifiers - fi - ;; *) #find first command if [[ ${COMP_CWORD} = 1 ]]; then diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 6062e2e50..e5b05ffb3 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -1,4 +1,5 @@ _fwupdtool_cmd_list=( + 'build-firmware' 'get-details' 'get-devices' 'get-plugins' @@ -66,6 +67,23 @@ _fwupdtool() _show_modifiers fi ;; + build-firmware) + #file in + if [[ "$prev" = "$command" ]]; then + _filedir + #file out + elif [[ "$prev" = "${COMP_WORDS[2]}" ]]; then + _filedir + #script + elif [[ "$prev" = "${COMP_WORDS[3]}" ]]; then + _filedir + #output + elif [[ "$prev" = "${COMP_WORDS[4]}" ]]; then + _filedir + else + _show_modifiers + fi + ;; *) #find first command if [[ ${COMP_CWORD} = 1 ]]; then diff --git a/src/fu-tool.c b/src/fu-tool.c index 858c90311..8a1605971 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -906,6 +906,33 @@ fu_util_hwids (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_firmware_builder (FuUtilPrivate *priv, gchar **values, GError **error) +{ + const gchar *script_fn = "startup.sh"; + const gchar *output_fn = "firmware.bin"; + g_autoptr(GBytes) archive_blob = NULL; + g_autoptr(GBytes) firmware_blob = NULL; + if (g_strv_length (values) < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + archive_blob = fu_common_get_contents_bytes (values[0], error); + if (archive_blob == NULL) + return FALSE; + if (g_strv_length (values) > 2) + script_fn = values[2]; + if (g_strv_length (values) > 3) + output_fn = values[3]; + firmware_blob = fu_common_firmware_builder (archive_blob, script_fn, output_fn, error); + if (firmware_blob == NULL) + return FALSE; + return fu_common_set_contents_bytes (values[1], firmware_blob, error); +} + int main (int argc, char *argv[]) { @@ -957,6 +984,12 @@ main (int argc, char *argv[]) /* add commands */ priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_util_item_free); + fu_util_add (priv->cmd_array, + "build-firmware", + "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]", + /* TRANSLATORS: command description */ + _("Build firmware using a sandbox"), + fu_util_firmware_builder); fu_util_add (priv->cmd_array, "smbios-dump", "FILE", diff --git a/src/fu-util.c b/src/fu-util.c index 147e430b3..6da7b02a4 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1970,33 +1970,6 @@ fu_util_changed_cb (FwupdClient *client, gpointer user_data) g_print ("%s\n", _("Changed")); } -static gboolean -fu_util_firmware_builder (FuUtilPrivate *priv, gchar **values, GError **error) -{ - const gchar *script_fn = "startup.sh"; - const gchar *output_fn = "firmware.bin"; - g_autoptr(GBytes) archive_blob = NULL; - g_autoptr(GBytes) firmware_blob = NULL; - if (g_strv_length (values) < 2) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "Invalid arguments"); - return FALSE; - } - archive_blob = fu_common_get_contents_bytes (values[0], error); - if (archive_blob == NULL) - return FALSE; - if (g_strv_length (values) > 2) - script_fn = values[2]; - if (g_strv_length (values) > 3) - output_fn = values[3]; - firmware_blob = fu_common_firmware_builder (archive_blob, script_fn, output_fn, error); - if (firmware_blob == NULL) - return FALSE; - return fu_common_set_contents_bytes (values[1], firmware_blob, error); -} - static gboolean fu_util_monitor (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -2503,12 +2476,6 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Monitor the daemon for events"), fu_util_monitor); - fu_util_add (priv->cmd_array, - "build-firmware", - "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]", - /* TRANSLATORS: command description */ - _("Build firmware using a sandbox"), - fu_util_firmware_builder); fu_util_add (priv->cmd_array, "modify-remote", "REMOTE-ID KEY VALUE", From 62f8486ffe8b6b61ad6be4f39c96aa064a05f198 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 18 Oct 2018 13:15:23 -0500 Subject: [PATCH 036/254] fwupdmgr/fwupdtool: Move monitor command to fwupdtool This command is used for monitoring events from the daemon and normally used only by power users or developers. --- data/bash-completion/fwupdmgr | 1 - data/bash-completion/fwupdtool.in | 1 + src/fu-tool.c | 67 ++++++++++++++++++++++++++++ src/fu-util.c | 74 ------------------------------- 4 files changed, 68 insertions(+), 75 deletions(-) diff --git a/data/bash-completion/fwupdmgr b/data/bash-completion/fwupdmgr index 495556a47..631d09ee5 100644 --- a/data/bash-completion/fwupdmgr +++ b/data/bash-completion/fwupdmgr @@ -16,7 +16,6 @@ _fwupdmgr_cmd_list=( 'install' 'install-prepared' 'modify-remote' - 'monitor' 'refresh' 'report-history' 'unlock' diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index e5b05ffb3..86758ce0c 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -7,6 +7,7 @@ _fwupdtool_cmd_list=( 'hwids' 'install' 'install-blob' + 'monitor' 'smbios-dump' 'attach' 'detach' diff --git a/src/fu-tool.c b/src/fu-tool.c index 8a1605971..c8eca93b6 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -933,6 +933,67 @@ fu_util_firmware_builder (FuUtilPrivate *priv, gchar **values, GError **error) return fu_common_set_contents_bytes (values[1], firmware_blob, error); } +static void +fu_util_device_added_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device is hotplugged */ + g_print ("%s\n%s", _("Device added:"), tmp); +} + +static void +fu_util_device_removed_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device is hotplugged */ + g_print ("%s\n%s", _("Device removed:"), tmp); +} + +static void +fu_util_device_changed_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device has been updated */ + g_print ("%s\n%s", _("Device changed:"), tmp); +} + +static void +fu_util_changed_cb (FwupdClient *client, gpointer user_data) +{ + /* TRANSLATORS: this is when the daemon state changes */ + g_print ("%s\n", _("Changed")); +} + +static gboolean +fu_util_monitor (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FwupdClient) client = fwupd_client_new (); + + /* get all the devices */ + if (!fwupd_client_connect (client, priv->cancellable, error)) + return FALSE; + + /* watch for any hotplugged device */ + g_signal_connect (client, "changed", + G_CALLBACK (fu_util_changed_cb), priv); + g_signal_connect (client, "device-added", + G_CALLBACK (fu_util_device_added_cb), priv); + g_signal_connect (client, "device-removed", + G_CALLBACK (fu_util_device_removed_cb), priv); + g_signal_connect (client, "device-changed", + G_CALLBACK (fu_util_device_changed_cb), priv); + g_signal_connect (priv->cancellable, "cancelled", + G_CALLBACK (fu_util_cancelled_cb), priv); + g_main_loop_run (priv->loop); + return TRUE; +} + int main (int argc, char *argv[]) { @@ -1056,6 +1117,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Return all the hardware IDs for the machine"), fu_util_hwids); + fu_util_add (priv->cmd_array, + "monitor", + NULL, + /* TRANSLATORS: command description */ + _("Monitor the daemon for events"), + fu_util_monitor); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); diff --git a/src/fu-util.c b/src/fu-util.c index 6da7b02a4..e218aa0ee 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1924,74 +1924,6 @@ fu_util_get_remotes (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } -static void -fu_util_cancelled_cb (GCancellable *cancellable, gpointer user_data) -{ - FuUtilPrivate *priv = (FuUtilPrivate *) user_data; - /* TRANSLATORS: this is when a device ctrl+c's a watch */ - g_print ("%s\n", _("Cancelled")); - g_main_loop_quit (priv->loop); -} - -static void -fu_util_device_added_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device is hotplugged */ - g_print ("%s\n%s", _("Device added:"), tmp); -} - -static void -fu_util_device_removed_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device is hotplugged */ - g_print ("%s\n%s", _("Device removed:"), tmp); -} - -static void -fu_util_device_changed_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device has been updated */ - g_print ("%s\n%s", _("Device changed:"), tmp); -} - -static void -fu_util_changed_cb (FwupdClient *client, gpointer user_data) -{ - /* TRANSLATORS: this is when the daemon state changes */ - g_print ("%s\n", _("Changed")); -} - -static gboolean -fu_util_monitor (FuUtilPrivate *priv, gchar **values, GError **error) -{ - /* get all the devices */ - if (!fwupd_client_connect (priv->client, priv->cancellable, error)) - return FALSE; - - /* watch for any hotplugged device */ - g_signal_connect (priv->client, "changed", - G_CALLBACK (fu_util_changed_cb), priv); - g_signal_connect (priv->client, "device-added", - G_CALLBACK (fu_util_device_added_cb), priv); - g_signal_connect (priv->client, "device-removed", - G_CALLBACK (fu_util_device_removed_cb), priv); - g_signal_connect (priv->client, "device-changed", - G_CALLBACK (fu_util_device_changed_cb), priv); - g_signal_connect (priv->cancellable, "cancelled", - G_CALLBACK (fu_util_cancelled_cb), priv); - g_main_loop_run (priv->loop); - return TRUE; -} - static gboolean fu_util_update_device_with_release (FuUtilPrivate *priv, FwupdDevice *dev, @@ -2470,12 +2402,6 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Update the stored metadata with current ROM contents"), fu_util_verify_update); - fu_util_add (priv->cmd_array, - "monitor", - NULL, - /* TRANSLATORS: command description */ - _("Monitor the daemon for events"), - fu_util_monitor); fu_util_add (priv->cmd_array, "modify-remote", "REMOTE-ID KEY VALUE", From 0cc1ff5cd73ad6494157e1dc4cafb7d60afdd93f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 18 Oct 2018 19:35:55 +0100 Subject: [PATCH 037/254] amt: Set the full device version including the BuildNum --- plugins/amt/fu-plugin-amt.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/plugins/amt/fu-plugin-amt.c b/plugins/amt/fu-plugin-amt.c index e68223176..1f74c1622 100644 --- a/plugins/amt/fu-plugin-amt.c +++ b/plugins/amt/fu-plugin-amt.c @@ -375,6 +375,8 @@ fu_plugin_amt_create_device (GError **error) uuid_t uu; g_autofree struct amt_host_if_resp_header *response = NULL; g_autoptr(FuDevice) dev = NULL; + g_autoptr(GString) version_bl = g_string_new (NULL); + g_autoptr(GString) version_fw = g_string_new (NULL); g_autoptr(mei_context) ctx = g_new0 (mei_context, 1); const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \ @@ -449,15 +451,29 @@ fu_plugin_amt_create_device (GError **error) /* get version numbers */ for (guint i = 0; i < ver.count; i++) { if (g_strcmp0 (ver.versions[i].description.string, "AMT") == 0) { - fu_device_set_version (dev, ver.versions[i].version.string); + g_string_append (version_fw, ver.versions[i].version.string); continue; } - if (g_strcmp0 (ver.versions[i].description.string, - "Recovery Version") == 0) { - fu_device_set_version_bootloader (dev, ver.versions[i].version.string); + if (g_strcmp0 (ver.versions[i].description.string, "Recovery Version") == 0) { + g_string_append (version_bl, ver.versions[i].version.string); + continue; + } + if (g_strcmp0 (ver.versions[i].description.string, "Build Number") == 0) { + g_string_append_printf (version_fw, ".%s", + ver.versions[i].version.string); + continue; + } + if (g_strcmp0 (ver.versions[i].description.string, "Recovery Build Num") == 0) { + g_string_append_printf (version_bl, ".%s", + ver.versions[i].version.string); continue; } } + if (version_fw->len > 0) + fu_device_set_version (dev, version_fw->str); + if (version_bl->len > 0) + fu_device_set_version_bootloader (dev, version_bl->str); + return g_steal_pointer (&dev); } From a8240caf2ea33eae71dfed0ed247af58f17ab58d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 17 Oct 2018 14:12:07 -0500 Subject: [PATCH 038/254] trivial: snap: Use libxmlb subproject instead This avoids having to bump the snap on libxmlb releases. --- contrib/snap/snapcraft-master.yaml | 36 +++--------------------------- snap/snapcraft.yaml | 35 +++-------------------------- 2 files changed, 6 insertions(+), 65 deletions(-) diff --git a/contrib/snap/snapcraft-master.yaml b/contrib/snap/snapcraft-master.yaml index a241f1c89..c443ae055 100644 --- a/contrib/snap/snapcraft-master.yaml +++ b/contrib/snap/snapcraft-master.yaml @@ -80,38 +80,6 @@ parts: - -lib - -share - -usr - libxmlb-dev: - plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false] - source: https://github.com/hughsie/libxmlb - source-type: git - build-packages: - - python3-pip - - libgirepository1.0-dev - - libglib2.0-dev - - libgtk-3-dev - - libjson-glib-dev - - uuid-dev - prime: - - -usr/bin - - -usr/include - - -usr/share/doc - - -usr/share/bash-completion - - -usr/share/aclocal - - -usr/lib/*/pkgconfig - - -usr/share/installed-tests - - -usr/lib/systemd - - -usr/lib/glib-networking - - -usr/lib/dconf - - -usr/share/X11 - - -usr/share/GConf - - -usr/share/dbus-1 - - -usr/share/glib-2.0/schemas - - -usr/share/lintian - - -usr/share/man - - -usr/lib/*/gdk-pixbuf-2.0 - - -usr/share/gettext - after: [meson] gudev: plugin: autotools source: https://gitlab.gnome.org/GNOME/libgudev.git @@ -222,6 +190,8 @@ parts: -Dintrospection=false, -Dman=false, -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + -Dlibxmlb:gtkdoc=false, + -Dlibxmlb:introspection=false, -Dpkcs7=false] source: . source-type: git @@ -294,7 +264,7 @@ parts: - -usr/share/gir-1.0 - -usr/share/upstart - -usr/lib/*/pkgconfig - after: [libxmlb-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] + after: [gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 5e4a295b0..ad7659eea 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -77,37 +77,6 @@ parts: - -lib - -share - -usr - libxmlb-dev: - plugin: meson - meson-parameters: [--prefix=/usr, -Dgtk-doc=false, -Dintrospection=false] - source: https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.2.tar.xz - build-packages: - - python3-pip - - libgirepository1.0-dev - - libglib2.0-dev - - libgtk-3-dev - - libjson-glib-dev - - uuid-dev - prime: - - -usr/bin - - -usr/include - - -usr/share/doc - - -usr/share/bash-completion - - -usr/share/aclocal - - -usr/lib/*/pkgconfig - - -usr/share/installed-tests - - -usr/lib/systemd - - -usr/lib/glib-networking - - -usr/lib/dconf - - -usr/share/X11 - - -usr/share/GConf - - -usr/share/dbus-1 - - -usr/share/glib-2.0/schemas - - -usr/share/lintian - - -usr/share/man - - -usr/lib/*/gdk-pixbuf-2.0 - - -usr/share/gettext - after: [meson] gudev: plugin: autotools source: https://github.com/GNOME/libgudev/archive/232.tar.gz @@ -217,6 +186,8 @@ parts: -Dintrospection=false, -Dman=false, -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + "-Dlibxmlb:gtkdoc=false", + "-Dlibxmlb:introspection=false", -Dpkcs7=false] source: . source-type: git @@ -289,7 +260,7 @@ parts: - -usr/share/gir-1.0 - -usr/share/upstart - -usr/lib/*/pkgconfig - after: [libxmlb-dev, gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] + after: [gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext] fix-bash-completion: plugin: make source: contrib/snap/fix-bash-completion From 2aaa38d77df06f10968bda089156a29446435141 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Oct 2018 07:50:26 -0500 Subject: [PATCH 039/254] trivial: debian: Make control file statement more generic (Closes: #911505) --- contrib/debian/control.in | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/contrib/debian/control.in b/contrib/debian/control.in index 47b8943d8..741c3fb8f 100644 --- a/contrib/debian/control.in +++ b/contrib/debian/control.in @@ -22,8 +22,7 @@ Description: Firmware update daemon library fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the library used by the daemon. @@ -46,8 +45,7 @@ Description: Firmware update daemon fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details Package: fwupd-tests @@ -69,8 +67,7 @@ Description: Test suite for firmware update daemon fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides a set of installed tests that can be run to validate @@ -85,8 +82,7 @@ Description: Firmware update daemon documentation (HTML format) fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides development documentation for creating a package that @@ -105,8 +101,7 @@ Description: development files for libfwupd fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the development files for libfwupd From 60c4a59dabc42ca0a87dfe6236061a9a5ce9075f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Oct 2018 14:00:59 -0500 Subject: [PATCH 040/254] trivial: dell-dock: Lower MST communication speed to 400 KHz It was identified that at least one other device on this shared I2C bus can't operate at the speed. This means that it may inadvertently respond to commands intended for another device. --- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index 21887fb3f..a57e66bad 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -98,7 +98,7 @@ const MSTBankAttributes esm_attributes = { FuHIDI2CParameters mst_base_settings = { .i2cslaveaddr = I2C_MST_ADDRESS, .regaddrlen = 0, - .i2cspeed = I2C_SPEED_800K, + .i2cspeed = I2C_SPEED_400K, }; struct _FuDellDockMst { From 72b7eab6930888bb91f1f8b0a40b88ceda3b4f08 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 23 Oct 2018 08:16:41 +0100 Subject: [PATCH 041/254] flatpak: Update gnu-efi to latest version --- contrib/org.freedesktop.fwupd.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/org.freedesktop.fwupd.json b/contrib/org.freedesktop.fwupd.json index 6cfa67215..ee44322b5 100644 --- a/contrib/org.freedesktop.fwupd.json +++ b/contrib/org.freedesktop.fwupd.json @@ -155,8 +155,8 @@ "sources": [ { "type": "archive", - "url": "http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.5.tar.bz2", - "sha256": "bd8fcd5914f18fc0e4ba948ab03b00013e528504f529c60739b748f6ef130b22" + "url": "http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.9.tar.bz2", + "sha256": "6715ea7eae1c7e4fc5041034bd3f107ec2911962ed284a081e491646b12277f0" } ] }, From e4ad25044a07fbcea4d719a1a9776abc58a2d1f7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 19 Oct 2018 11:09:36 +0100 Subject: [PATCH 042/254] Sort the firmware sack by component priority This allows composite firmware to be ordered in an explicit way. --- contrib/ci/Dockerfile-fedora.in | 2 +- contrib/ci/Dockerfile-flatpak.in | 1 + contrib/ci/dependencies.xml | 4 ++-- contrib/ci/flatpak.sh | 4 ++-- contrib/fwupd.spec.in | 2 +- contrib/org.freedesktop.fwupd.json | 6 +++--- meson.build | 2 +- src/fu-common-cab.c | 30 ++++++++++++++++++++++++++++++ subprojects/libxmlb.wrap | 2 +- 9 files changed, 42 insertions(+), 11 deletions(-) diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index 09cdbae13..99dd1690b 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -5,7 +5,7 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id RUN dnf --enablerepo=updates-testing -y update -RUN dnf install -y https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.2/1.fc29/x86_64/libxmlb-0.1.2-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.2/1.fc29/x86_64/libxmlb-devel-0.1.2-1.fc29.x86_64.rpm +RUN dnf install -y https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.3/1.fc29/x86_64/libxmlb-0.1.3-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.3/1.fc29/x86_64/libxmlb-devel-0.1.3-1.fc29.x86_64.rpm RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN mkdir /build diff --git a/contrib/ci/Dockerfile-flatpak.in b/contrib/ci/Dockerfile-flatpak.in index 09b9ef951..1dc25e97d 100644 --- a/contrib/ci/Dockerfile-flatpak.in +++ b/contrib/ci/Dockerfile-flatpak.in @@ -5,6 +5,7 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% +RUN dnf --enablerepo=updates-testing -y update RUN mkdir /build WORKDIR /build COPY . . diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index fc688fdaf..1bb84c86b 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -555,7 +555,7 @@ - (>= 0.1.2) + (>= 0.1.3) libxmlb-dev:s390x @@ -563,7 +563,7 @@ - (>= 0.1.2) + (>= 0.1.3) diff --git a/contrib/ci/flatpak.sh b/contrib/ci/flatpak.sh index 425299e13..51feb278d 100755 --- a/contrib/ci/flatpak.sh +++ b/contrib/ci/flatpak.sh @@ -4,8 +4,8 @@ set -x # install the runtimes flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo -flatpak install --assumeyes flathub runtime/org.gnome.Sdk/x86_64/3.28 -flatpak install --assumeyes flathub runtime/org.gnome.Platform/x86_64/3.28 +flatpak install --assumeyes flathub runtime/org.gnome.Sdk/x86_64/3.30 +flatpak install --assumeyes flathub runtime/org.gnome.Platform/x86_64/3.30 # build the repo flatpak-builder --repo=repo --force-clean --disable-rofiles-fuse build-dir contrib/org.freedesktop.fwupd.json diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 06b72aafd..507f0d294 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -1,5 +1,5 @@ %global glib2_version 2.45.8 -%global libxmlb_version 0.1.2 +%global libxmlb_version 0.1.3 %global libgusb_version 0.2.11 %global libsoup_version 2.51.92 %global systemd_version 231 diff --git a/contrib/org.freedesktop.fwupd.json b/contrib/org.freedesktop.fwupd.json index ee44322b5..87df56d02 100644 --- a/contrib/org.freedesktop.fwupd.json +++ b/contrib/org.freedesktop.fwupd.json @@ -1,7 +1,7 @@ { "app-id": "org.freedesktop.fwupd", "runtime": "org.gnome.Platform", - "runtime-version": "3.28", + "runtime-version": "3.30", "branch": "master", "sdk": "org.gnome.Sdk", "command": "/app/libexec/fwupd/fwupdtool", @@ -215,8 +215,8 @@ "sources": [ { "type": "archive", - "url": "https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.2.tar.xz", - "sha256": "20a734895830ae2af82a270b61e4832c6012b1aaf2003e1300d743dbd6aa95cf" + "url": "https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.3.tar.xz", + "sha256": "b609a95d078ab956231a43fd082382b386ed2f90e3fe5e8b785c4278a1b4787e" } ] }, diff --git a/meson.build b/meson.build index ab10bfc13..737841f1a 100644 --- a/meson.build +++ b/meson.build @@ -154,7 +154,7 @@ gudev = dependency('gudev-1.0') if gudev.version().version_compare('>= 232') conf.set('HAVE_GUDEV_232', '1') endif -libxmlb = dependency('xmlb', version : '>= 0.1.2', fallback : ['libxmlb', 'libxmlb_dep']) +libxmlb = dependency('xmlb', version : '>= 0.1.3', fallback : ['libxmlb', 'libxmlb_dep']) gusb = dependency('gusb', version : '>= 0.2.9') sqlite = dependency('sqlite3') libarchive = dependency('libarchive') diff --git a/src/fu-common-cab.c b/src/fu-common-cab.c index f816f0b03..7dee87959 100644 --- a/src/fu-common-cab.c +++ b/src/fu-common-cab.c @@ -301,6 +301,28 @@ fu_common_store_file_cb (GCabFile *file, gpointer user_data) return TRUE; } +static gint +fu_common_cab_sort_cb (XbBuilderNode *bn1, XbBuilderNode *bn2, gpointer user_data) +{ + guint64 prio1 = xb_builder_node_get_attr_as_uint (bn1, "priority"); + guint64 prio2 = xb_builder_node_get_attr_as_uint (bn2, "priority"); + if (prio1 > prio2) + return -1; + if (prio1 < prio2) + return 1; + return 0; +} + +static gboolean +fu_common_cab_sort_priority_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + xb_builder_node_sort_children (bn, fu_common_cab_sort_cb, user_data); + return TRUE; +} + /** * fu_common_cab_build_silo: * @blob: A readable blob @@ -326,11 +348,19 @@ fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) #endif g_autoptr(XbSilo) silo = NULL; g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderFixup) fixup = NULL; g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) ip = NULL; g_autoptr(GPtrArray) components = NULL; + /* sort the components by priority */ + fixup = xb_builder_fixup_new ("OrderByPriority", + fu_common_cab_sort_priority_cb, + NULL, NULL); + xb_builder_fixup_set_max_depth (fixup, 0); + xb_builder_add_fixup (builder, fixup); + /* load from a seekable stream */ ip = g_memory_input_stream_new_from_bytes (blob); if (!gcab_cabinet_load (cabinet, ip, NULL, error)) diff --git a/subprojects/libxmlb.wrap b/subprojects/libxmlb.wrap index bcf554748..f64c8a729 100644 --- a/subprojects/libxmlb.wrap +++ b/subprojects/libxmlb.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = libxmlb url = https://github.com/hughsie/libxmlb.git -revision = wip/subproject +revision = 0.1.3 From 355f5c12d65179fe42d237be46ffe0848f959be4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 22 Oct 2018 16:52:56 -0500 Subject: [PATCH 043/254] firmware-packager: Make it clearer to use 1) Remove the confusing --firmware-id and build this field dynamically based on GUID and Developer name 2) Make developer name mandatory 3) Rename device-unique-id to device-guid to more closely reflect how fwupdmgr shows it 4) Allow running on Windows --- contrib/firmware-packager/README.md | 6 ++--- contrib/firmware-packager/firmware-packager | 27 ++++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/contrib/firmware-packager/README.md b/contrib/firmware-packager/README.md index db066d79d..894a94bff 100644 --- a/contrib/firmware-packager/README.md +++ b/contrib/firmware-packager/README.md @@ -26,21 +26,19 @@ bin file inside the archive, I would pass `--exe dell-thunderbolt-firmware.exe - ## Documentation -`--firmware-id` ID for the firmware package, can be a customized [fwupd.org](http://fwupd.org/vendors.html) recommends using "a reverse-DNS prefix similar to java" and to "always use a .firmware suffix" (e.g. net.queuecumber.DellTBT.firmware) **REQUIRED** - `--firmware-name` Short name of the firmware package can be customized (e.g. DellTBT) **REQUIRED** `--firmware-summary` One line description of the firmware package (e.g. Dell thunderbolt firmware) `--firmware-description` Longer description of the firmware package. Theoretically this can include HTML but I haven't tried it -`--device-unique-id` Unique ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED** +`--device-guid` GUID ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED** `--firmware-homepage` Website for the firmware provider (e.g. http://www.dell.com) `-contact-info` Email address of the firmware developer (e.g. someone@something.net) -`--developer-name` Name of the firmware developer (e.g. John Smith) +`--developer-name` Name of the firmware developer (e.g. Dell) **REQUIRED** `--release-version` Version number of the firmware package (e.g. 4.21.01.002) **REQUIRED** `--release-description` Description of the firmware release, again this can theoretically include HTML but I didnt try it. diff --git a/contrib/firmware-packager/firmware-packager b/contrib/firmware-packager/firmware-packager index 531d4f958..e6065d766 100755 --- a/contrib/firmware-packager/firmware-packager +++ b/contrib/firmware-packager/firmware-packager @@ -24,14 +24,14 @@ def cd(path): firmware_metainfo_template = """ - {firmware_id} + org.{developer_name}.guid{firmware_id} {firmware_name} {firmware_summary} {firmware_description} - {device_unique_id} + {device_guid} {firmware_homepage} CC0-1.0 @@ -50,7 +50,9 @@ firmware_metainfo_template = """ def make_firmware_metainfo(firmware_info, dst): - firmware_metainfo = firmware_metainfo_template.format(**vars(firmware_info), timestamp=time.time()) + local_info = vars(firmware_info) + local_info["firmware_id"] = local_info["device_guid"][0:8] + firmware_metainfo = firmware_metainfo_template.format(**local_info, timestamp=time.time()) with open(os.path.join(dst, 'firmware.metainfo.xml'), 'w') as f: f.write(firmware_metainfo) @@ -68,7 +70,15 @@ def get_firmware_bin(root, bin_path, dst): def create_firmware_cab(exe, folder): with cd(folder): - command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml'] + if os.name is "nt": + directive = os.path.join (folder, "directive") + with open (directive, 'w') as wfd: + wfd.write('"firmware.cab"\r\n') + wfd.write('"firmware.bin"\r\n') + wfd.write('"firmware.metainfo.xml"\r\n') + command = ['makecab.exe', '/f', directive] + else: + command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml'] subprocess.check_call(command) @@ -93,18 +103,17 @@ def main(args): shutil.copy(os.path.join(dir, 'firmware.cab'), args.out) parser = argparse.ArgumentParser(description='Create fwupd packaged from windows executables') -parser.add_argument('--firmware-id', help='ID for the firmware package, can be a customized (e.g. net.queuecumber.DellTBT.firmware)', required=True) parser.add_argument('--firmware-name', help='Name of the firmware package can be customized (e.g. DellTBT)', required=True) parser.add_argument('--firmware-summary', help='One line description of the firmware package') parser.add_argument('--firmware-description', help='Longer description of the firmware package') -parser.add_argument('--device-unique-id', help='Unique ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices`', required=True) +parser.add_argument('--device-guid', help='GUID of the device this firmware will run on, this *must* match the output of one of the GUIDs in `fwupdmgr get-devices`', required=True) parser.add_argument('--firmware-homepage', help='Website for the firmware provider') parser.add_argument('--contact-info', help='Email address of the firmware developer') -parser.add_argument('--developer-name', help='Name of the firmware developer') +parser.add_argument('--developer-name', help='Name of the firmware developer', required=True) parser.add_argument('--release-version', help='Version number of the firmware package', required=True) parser.add_argument('--release-description', help='Description of the firmware release') -parser.add_argument('--exe', help='Executable file to extract firmware from') -parser.add_argument('--bin', help='Path to the .bin file inside the executable to use as the firmware image', required=True) +parser.add_argument('--exe', help='(optional) Executable file to extract firmware from') +parser.add_argument('--bin', help='Path to the .bin file (Relative if inside the executable; Absolute if outside) to use as the firmware image', required=True) parser.add_argument('--out', help='Output cab file path', required=True) args = parser.parse_args() From ab8849aee1ee5c87a8d1d31ac6f8e3eec51d5978 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 24 Oct 2018 12:21:48 +0100 Subject: [PATCH 044/254] Use HTTPS_PROXY if set Apparently, most application support both the lower and upper case versions... Fixes https://github.com/hughsie/fwupd/issues/815 --- src/fu-util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fu-util.c b/src/fu-util.c index e218aa0ee..c8176ee5c 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -317,8 +317,12 @@ fu_util_setup_networking (FuUtilPrivate *priv, GError **error) /* set the proxy */ http_proxy = g_getenv ("https_proxy"); + if (http_proxy == NULL) + http_proxy = g_getenv ("HTTPS_PROXY"); if (http_proxy == NULL) http_proxy = g_getenv ("http_proxy"); + if (http_proxy == NULL) + http_proxy = g_getenv ("HTTP_PROXY"); if (http_proxy != NULL) { g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy); if (proxy_uri == NULL) { From 343095ddb51ec3d6008fb8889fa493671c4eb147 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Oct 2018 17:21:13 -0500 Subject: [PATCH 045/254] trivial: fu-device-list: Return devices by priority --- src/fu-engine.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 04aa648e2..69baa552d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2228,6 +2228,21 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) return g_steal_pointer (&details); } +static gint +fu_engine_sort_devices_by_priority (gconstpointer a, gconstpointer b) +{ + FuDevice *dev_a = *((FuDevice **) a); + FuDevice *dev_b = *((FuDevice **) b); + gint prio_a = fu_device_get_priority (dev_a); + gint prio_b = fu_device_get_priority (dev_b); + + if (prio_a > prio_b) + return -1; + if (prio_a < prio_b) + return 1; + return 0; +} + /** * fu_engine_get_devices: * @self: A #FuEngine @@ -2253,6 +2268,7 @@ fu_engine_get_devices (FuEngine *self, GError **error) "No detected devices"); return NULL; } + g_ptr_array_sort (devices, fu_engine_sort_devices_by_priority); return g_steal_pointer (&devices); } From 387f039beaa71e8e03159954ad7892e52ef22396 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 23 Oct 2018 17:21:40 -0500 Subject: [PATCH 046/254] trivial: fu-engine: Increase the priority on a device if it has children This will cause devices with children to be displayed (and potentially processed) before children devices. --- src/fu-engine.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 69baa552d..bbf1bdf03 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2942,7 +2942,16 @@ fu_engine_plugin_device_added_cb (FuPlugin *plugin, gpointer user_data) { FuEngine *self = (FuEngine *) user_data; - fu_device_set_priority (device, fu_plugin_get_priority (plugin)); + gint priority = fu_plugin_get_priority (plugin); + GPtrArray *children = fu_device_get_children (device); + /* set the priority to 1 greater than biggest child */ + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + gint child_priority = fu_device_get_priority (child); + if (child_priority >= priority) + priority = child_priority + 1; + } + fu_device_set_priority (device, priority); fu_engine_add_device (self, device); } From 53b49458b61ca63204155283d75dab4812976964 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 31 Oct 2018 13:37:49 -0500 Subject: [PATCH 047/254] dell-dock: Prefer to flash VMM5331 via I2C instead of DP aux Although this is (currently) slower to flash with, bad behavior and corner case scenarios such as these don't occur: * Flickering during enumeration * Monitor plugged in during enumeration but not during flash * Heavy DP traffic slowing down update significantly * Sandboxes without access to `/dev/drm_dp_auxY` unable to flash * Exercising existing graphics driver bugs leading to system freezes. Additionally this removes a lot of code in dell_dock that was put in place specifically to be able to support waking up the MST hub to try to use DP aux for flashing. Now DP aux will only be used to flash when fwupd is compiled without `dell_dock`. --- plugins/dell-dock/fu-plugin-dell-dock.c | 68 +------------------ plugins/synapticsmst/fu-plugin-synapticsmst.c | 3 - 2 files changed, 3 insertions(+), 68 deletions(-) diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index b1b5e7f64..a8845e1a7 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -21,55 +21,15 @@ #include "fu-dell-dock-common.h" -struct FuPluginData { - gboolean synaptics_functional; -}; - void fu_plugin_init (FuPlugin *plugin) { - fu_plugin_alloc_data (plugin, sizeof(FuPluginData)); - /* allow these to be built by quirks */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); g_type_ensure (FU_TYPE_DELL_DOCK_STATUS); g_type_ensure (FU_TYPE_DELL_DOCK_MST); -} -static gboolean -fu_plugin_dell_dock_get_synaptics_unlock (FuPlugin *plugin, guint8 *target, - GError **error) -{ - const gchar *target_str = fu_plugin_lookup_quirk_by_id (plugin, - "DellDockUnlockTargets", - "synapticsmst"); - guint64 tmp; - - g_return_val_if_fail (target != NULL, FALSE); - - tmp = fu_common_strtoull (target_str); - if (tmp < G_MAXUINT8) { - *target = tmp; - return TRUE; - } - g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "Unsupported unlock target %s", - target_str); - return FALSE; -} - -void -fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) -{ - if (g_strcmp0 (fu_device_get_plugin (device), "synapticsmst") != 0) - return; - - /* not a perfect heuristic; but good enough - disable extra coldplug */ - if (fu_device_has_custom_flag (device, "skip-restart")) { - FuPluginData *data = fu_plugin_get_data (plugin); - g_debug ("%s registered via Synaptics MST plugin, disabling extra coldplug", - fu_device_get_name (device)); - data->synaptics_functional = TRUE; - } + /* currently slower performance, but more reliable in corner cases */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "synapticsmst"); } static gboolean @@ -111,7 +71,6 @@ fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuDellDockHub) hub = fu_dell_dock_hub_new (device); FuDevice *fu_device = FU_DEVICE (hub); @@ -141,15 +100,6 @@ fu_plugin_usb_device_added (FuPlugin *plugin, key, error_local->message); } - - /* reprobe for synaptics when adding bridge */ - g_debug ("Synaptics MST over DP aux functional: %d", data->synaptics_functional); -#if defined(HAVE_SYNAPTICS) - if (!data->synaptics_functional) { - fu_plugin_set_coldplug_delay (plugin, 2000); - fu_plugin_request_recoldplug (plugin); - } -#endif } return TRUE; @@ -158,7 +108,6 @@ fu_plugin_usb_device_added (FuPlugin *plugin, gboolean fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); const gchar *device_key = fu_device_get_id (device); FuDevice *dev; FuDevice *parent; @@ -176,8 +125,6 @@ fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) fu_device_get_name (parent), fu_device_get_id (parent)); fu_plugin_device_remove (plugin, parent); - /* we don't know this anymore */ - data->synaptics_functional = FALSE; } return TRUE; @@ -239,17 +186,8 @@ fu_plugin_composite_prepare (FuPlugin *plugin, for (guint i = 0; i < devices->len; i++) { FuDevice *dev = g_ptr_array_index (devices, i); - /* if synaptics is part of the transaction via DP aux turn it on */ - if (g_strcmp0 (fu_device_get_plugin (dev), "synapticsmst") == 0) { - guint8 target; - if (fu_device_get_parent (dev) != parent) - continue; - if (!fu_plugin_dell_dock_get_synaptics_unlock (plugin, &target, error)) - return FALSE; - if (!fu_dell_dock_set_power (parent, target, TRUE, error)) - return FALSE; /* if thunderbolt is part of transaction our family is leaving us */ - } else if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0) { + if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0) { if (fu_device_get_parent (dev) != parent) continue; fu_dell_dock_will_replug (parent); diff --git a/plugins/synapticsmst/fu-plugin-synapticsmst.c b/plugins/synapticsmst/fu-plugin-synapticsmst.c index 52149edd1..83c9eee93 100644 --- a/plugins/synapticsmst/fu-plugin-synapticsmst.c +++ b/plugins/synapticsmst/fu-plugin-synapticsmst.c @@ -463,7 +463,4 @@ fu_plugin_init (FuPlugin *plugin) { /* make sure dell is already coldplugged */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "dell"); - - /* dell-dock plugin uses a slower bus for flashing */ - fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } From d22f215a70fe2556025639f964b0aa943dcfc544 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 30 Oct 2018 12:02:45 -0500 Subject: [PATCH 048/254] contrib: Adjust flatpak build for moving to flathub Pull the based json file from https://github.com/flathub/org.freedesktop.fwupd And modify it as necessary (for changes in master) --- .gitmodules | 3 + contrib/ci/Dockerfile-flatpak.in | 2 +- contrib/ci/flatpak.py | 106 +++++++ contrib/ci/flatpak.sh | 33 --- contrib/flatpak | 1 + contrib/flatpak/pip-Makefile | 5 - contrib/org.freedesktop.fwupd.json | 276 ------------------ contrib/standalone-installer/assets/header.py | 2 +- contrib/standalone-installer/make.py | 19 +- 9 files changed, 129 insertions(+), 318 deletions(-) create mode 100644 .gitmodules create mode 100755 contrib/ci/flatpak.py delete mode 100755 contrib/ci/flatpak.sh create mode 160000 contrib/flatpak delete mode 100644 contrib/flatpak/pip-Makefile delete mode 100644 contrib/org.freedesktop.fwupd.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..70f1092f0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "contrib/flatpak"] + path = contrib/flatpak + url = https://github.com/flathub/org.freedesktop.fwupd diff --git a/contrib/ci/Dockerfile-flatpak.in b/contrib/ci/Dockerfile-flatpak.in index 1dc25e97d..21e2dd1d9 100644 --- a/contrib/ci/Dockerfile-flatpak.in +++ b/contrib/ci/Dockerfile-flatpak.in @@ -9,4 +9,4 @@ RUN dnf --enablerepo=updates-testing -y update RUN mkdir /build WORKDIR /build COPY . . -CMD ["./contrib/ci/flatpak.sh"] +CMD ["./contrib/ci/flatpak.py"] diff --git a/contrib/ci/flatpak.py b/contrib/ci/flatpak.py new file mode 100755 index 000000000..6e494ad5f --- /dev/null +++ b/contrib/ci/flatpak.py @@ -0,0 +1,106 @@ +#!/usr/bin/python3 +import subprocess +import os +import json +import shutil + +def prepare (target): + #clone the flatpak json + cmd = ['git', 'submodule', 'update', 'contrib/flatpak'] + subprocess.run (cmd, check=True) + + #clone the submodules for that + cmd = ['git', 'submodule', 'update', '--init', 'shared-modules/'] + subprocess.run (cmd, cwd='contrib/flatpak', check=True) + + #parse json + if os.path.isdir ('build'): + shutil.rmtree ('build') + data = {} + with open ('contrib/flatpak/org.freedesktop.fwupd.json', 'r') as rfd: + data = json.load (rfd) + platform = 'runtime/%s/x86_64/%s' % (data['runtime'], data['runtime-version']) + sdk = 'runtime/%s/x86_64/%s' % (data['sdk'], data['runtime-version']) + num_modules = len (data['modules']) + + #update to build from master + data["branch"] = "master" + has_libxmlb = False + for index in range(0, num_modules): + module = data['modules'][index] + if type (module) != dict or not 'name' in module: + continue + name = module['name'] + if 'libxmlb' in name: + has_libxmlb = True + continue + if not 'fwupd' in name: + continue + data['modules'][index]['sources'][0].pop ('url') + data['modules'][index]['sources'][0].pop ('sha256') + data['modules'][index]['sources'][0]['type'] = 'dir' + data['modules'][index]['sources'][0]['skip'] = [".git"] + data['modules'][index]['sources'][0]['path'] = ".." + + #add libxmlb (This should be dropped when new release to flathub) + if not has_libxmlb: + print ("Adding libxmlb into json") + libxmlb = {'name': 'libxmlb', + 'buildsystem': 'meson', + 'config-opts': [ + "-Dintrospection=false", + "-Dgtkdoc=false", + "-Dtests=false", + "--sysconfdir=/app/etc", + "--localstatedir=/var/data" + ], + 'cleanup': ['/libexec/xb-tool'], + 'sources': [{ + "type": "archive", + "url": "https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.3.tar.xz", + "sha256": "b609a95d078ab956231a43fd082382b386ed2f90e3fe5e8b785c4278a1b4787e" + }] + } + data['modules'].insert(num_modules-1, libxmlb) + + #write json + os.mkdir('build') + with open (target, 'w') as wfd: + json.dump(data, wfd, indent=4) + os.symlink ('../contrib/flatpak/shared-modules','build/shared-modules') + + # install the runtimes (parsed from json!) + repo = 'flathub' + repo_url = 'https://dl.flathub.org/repo/flathub.flatpakrepo' + print ("Installing dependencies") + cmd = ['flatpak', 'remote-add', '--if-not-exists', repo, repo_url] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'install', '--assumeyes', repo, sdk] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'install', '--assumeyes', repo, platform] + subprocess.run (cmd, check=True) + + +def build (target): + cmd = ['flatpak-builder', '--repo=repo', '--force-clean', '--disable-rofiles-fuse', 'build-dir', target] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'build-bundle', 'repo', 'fwupd.flatpak', 'org.freedesktop.fwupd'] + subprocess.run (cmd, check=True) + +if __name__ == '__main__': + t = os.path.join ('build', 'org.freedesktop.fwupd.json') + prepare (t) + build (t) + +# to run from the builddir: +# sudo flatpak-builder --run build-dir org.freedesktop.fwupd.json /app/libexec/fwupd/fwupdtool get-devices + +# install the single file bundle +# flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo +# flatpak install fwupd.flatpak + +# to run a shell in the same environment that flatpak sees: +# flatpak run --command=sh --devel org.freedesktop.fwupd + +# to run fwupdtool as root: +# sudo flatpak run org.freedesktop.fwupd --verbose get-devices diff --git a/contrib/ci/flatpak.sh b/contrib/ci/flatpak.sh deleted file mode 100755 index 51feb278d..000000000 --- a/contrib/ci/flatpak.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -set -e -set -x - -# install the runtimes -flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo -flatpak install --assumeyes flathub runtime/org.gnome.Sdk/x86_64/3.30 -flatpak install --assumeyes flathub runtime/org.gnome.Platform/x86_64/3.30 - -# build the repo -flatpak-builder --repo=repo --force-clean --disable-rofiles-fuse build-dir contrib/org.freedesktop.fwupd.json - -# show the files that were included -tree build-dir - -# build a single file bundle -flatpak build-bundle repo fwupd.flatpak org.freedesktop.fwupd - -# make available as a deliverable -cp fwupd.flatpak dist - -# to run from the builddir: -# sudo flatpak-builder --run build-dir org.freedesktop.fwupd.json /app/libexec/fwupd/fwupdtool get-devices - -# install the single file bundle -# flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo -# flatpak install fwupd.flatpak - -# to run a shell in the same environment that flatpak sees: -# flatpak run --command=sh --devel org.freedesktop.fwupd - -# to run fwupdtool as root: -# sudo flatpak run org.freedesktop.fwupd --verbose get-devices diff --git a/contrib/flatpak b/contrib/flatpak new file mode 160000 index 000000000..3e60bea4e --- /dev/null +++ b/contrib/flatpak @@ -0,0 +1 @@ +Subproject commit 3e60bea4e74e4143bb2524762092e3d6e1e8930f diff --git a/contrib/flatpak/pip-Makefile b/contrib/flatpak/pip-Makefile deleted file mode 100644 index 13387d906..000000000 --- a/contrib/flatpak/pip-Makefile +++ /dev/null @@ -1,5 +0,0 @@ -all: - python3 setup.py build - -install: - python3 setup.py install --prefix=/app ${ARGS} diff --git a/contrib/org.freedesktop.fwupd.json b/contrib/org.freedesktop.fwupd.json deleted file mode 100644 index 87df56d02..000000000 --- a/contrib/org.freedesktop.fwupd.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "app-id": "org.freedesktop.fwupd", - "runtime": "org.gnome.Platform", - "runtime-version": "3.30", - "branch": "master", - "sdk": "org.gnome.Sdk", - "command": "/app/libexec/fwupd/fwupdtool", - "finish-args": [ - "--device=all", - "--filesystem=/boot", - "--filesystem=/sys", - "--filesystem=xdg-download", - "--share=network", - "--system-talk-name=org.freedesktop.fwupd", - "--system-talk-name=org.freedesktop.UPower" - ], - "build-options": { - "cflags": "-O2 -g", - "cxxflags": "-O2 -g" - }, - "cleanup": [ - "*.a", - "*.la", - "/include", - "/lib/girepository-1.0", - "/lib/pkgconfig", - "/share/bash-completion", - "/share/dbus-1/system-services", - "/share/gir-1.0", - "/share/gtk-doc", - "/share/info", - "/share/man", - "/share/pkgconfig" - ], - "modules": [ - { - /* not using shared-modules as we need gudev */ - "name": "udev", - "rm-configure": true, - "config-opts": [ - "--disable-hwdb", - "--disable-logging", - "--disable-introspection", - "--disable-keymap", - "--disable-mtd_probe" - ], - "cleanup": [ - "/etc/udev", - "/libexec/*", - "/share/gtk-doc/html/libudev/", - "/sbin/udevadm" - ], - "sources": [ - { - "type": "archive", - "url": "http://kernel.org/pub/linux/utils/kernel/hotplug/udev-175.tar.bz2", - "sha256": "4c7937fe5a1521316ea571188745b9a00a9fdf314228cffc53a7ba9e5968b7ab" - }, - { - "type": "script", - "dest-filename": "autogen.sh", - "commands": [ - "autoreconf -vfi" - ] - } - ] - }, - { - "name": "libusb", - "config-opts": [ - "--disable-static" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2", - "sha256": "75aeb9d59a4fdb800d329a545c2e6799f732362193b465ea198f2aa275518157" - } - ] - }, - { - "name": "gusb", - "buildsystem": "meson", - "config-opts": [ - "-Ddocs=false", - "-Dvapi=false", - "-Dtests=false" - ], - "cleanup": [ - "/bin/gusbcmd" - ], - "sources": [ - { - "type": "archive", - "url": "https://people.freedesktop.org/~hughsient/releases/libgusb-0.3.0.tar.xz", - "sha256": "d8e7950f99b6ae4c3e9b8c65f3692b9635289e6cff8de40c4af41b2e9b348edc" - } - ] - }, - { - "name": "efivar", - "buildsystem": "simple", - "build-commands": [ - "make prefix=/app libdir=/app/lib", - "make install prefix=/app libdir=/app/lib" - ], - "cleanup": [ - "/bin/efivar" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2", - "sha256": "1e033dc5d099a44fd473b0887dbcc4b105613efab0fb3c5df9f111ea5d147394" - } - ] - }, - { - "name": "libsmbios_c", - "only-arches": [ - "x86_64" - ], - "config-opts": [ - "--disable-doxygen", - "--disable-graphviz", - "--disable-python" - ], - "cleanup": [ - "/sbin/smbios*", - "/share/locale/*/LC_MESSAGES/libsmbios.mo" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/dell/libsmbios/archive/v2.4.2.tar.gz", - "sha256": "ebfe18415e24bbec06d0a9ea1066c8dcd82982555373712713d7e194138650de" - } - ] - }, - { - "name": "gnu-efi", - "only-arches": [ - "aarch64", - "x86_64" - ], - "buildsystem": "simple", - "build-commands": [ - "make", - "make PREFIX=/app install" - ], - "no-autogen": true, - "cleanup": [ - "/bin/efivar" - ], - "sources": [ - { - "type": "archive", - "url": "http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.9.tar.bz2", - "sha256": "6715ea7eae1c7e4fc5041034bd3f107ec2911962ed284a081e491646b12277f0" - } - ] - }, - { - "name": "python3-olefile", - "only-arches": [ - "aarch64", - "x86_64" - ], - "buildsystem": "simple", - "build-commands": [ - "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} olefile" - ], - "sources": [ - { - "type": "file", - "url": "https://pypi.python.org/packages/35/17/c15d41d5a8f8b98cc3df25eb00c5cee76193114c78e5674df6ef4ac92647/olefile-0.44.zip", - "sha256": "61f2ca0cd0aa77279eb943c07f607438edf374096b66332fae1ee64a6f0f73ad" - } - ] - }, - { - "name": "python3-pillow", - "only-arches": [ - "aarch64", - "x86_64" - ], - "buildsystem": "simple", - "build-commands": [ - "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} Pillow" - ], - "cleanup": [ - "/bin/*.py" - ], - "sources": [ - { - "type": "file", - "url": "https://pypi.python.org/packages/93/73/66854f63b1941aad9af18a1de59f9cf95ad1a87c801540222e332f6688d7/Pillow-4.1.1.tar.gz", - "sha256": "00b6a5f28d00f720235a937ebc2f50f4292a5c7e2d6ab9a8b26153b625c4f431" - } - ] - }, - { - "name": "libxmlb", - "buildsystem": "meson", - "config-opts": [ - "-Dintrospection=false", - "-Dgtkdoc=false", - "-Dtests=false", - "--sysconfdir=/app/etc", - "--localstatedir=/var/data" - ], - "cleanup": [ - "/libexec/xb-tool" - ], - "sources": [ - { - "type": "archive", - "url": "https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.3.tar.xz", - "sha256": "b609a95d078ab956231a43fd082382b386ed2f90e3fe5e8b785c4278a1b4787e" - } - ] - }, - { - "name": "fwupd", - "buildsystem": "meson", - "config-opts": [ - "-Dconsolekit=false", - "-Ddaemon=false", - "-Dgpg=false", - "-Dgtkdoc=false", - "-Dintrospection=false", - "-Dman=false", - "-Dpkcs7=false", - "-Dsystemd=false", - "-Dtests=false", - "-Defi-includedir=/app/include/efi", - "-Defi-ldsdir=/app/lib", - "-Defi-libdir=/app/lib", - "--sysconfdir=/app/etc", - "--localstatedir=/var/data" - ], - "build-options" : { - "arch": { - "i386": { - "config-opts": [ - "-Dplugin_dell=false", - "-Dplugin_uefi=false" - ] - }, - "arm": { - "config-opts": [ - "-Dplugin_dell=false", - "-Dplugin_uefi=false" - ] - }, - "aarch64": { - "config-opts": [ - "-Dplugin_dell=false" - ] - } - } - }, - "cleanup": [ - "/etc/dbus-1/system.d/org.freedesktop.fwupd.conf", - "/share/fwupd/remotes.d/vendor" - ], - "sources": [ - { - "type": "dir", - "skip": [".git"], - "path": ".." - } - ] - } - ] -} diff --git a/contrib/standalone-installer/assets/header.py b/contrib/standalone-installer/assets/header.py index 058ee3896..262360b09 100644 --- a/contrib/standalone-installer/assets/header.py +++ b/contrib/standalone-installer/assets/header.py @@ -128,7 +128,7 @@ def install_flatpak (directory, verbose, uninstall): else: output = None #look for dependencies - dep = 'org.gnome.Platform/x86_64/3.28' + dep = 'org.gnome.Platform/x86_64/3.30' repo = 'flathub' repo_url = 'https://flathub.org/repo/flathub.flatpakrepo' cmd = ['flatpak', 'info', dep] diff --git a/contrib/standalone-installer/make.py b/contrib/standalone-installer/make.py index ddd623837..7b76c8f2c 100755 --- a/contrib/standalone-installer/make.py +++ b/contrib/standalone-installer/make.py @@ -85,8 +85,23 @@ def download_cab_file (directory, uri): subprocess.run (cmd, cwd=directory, check=True) def download_flatpak (directory): - cmd = ['wget', 'https://people.freedesktop.org/~hughsient/temp/fwupd.flatpak', '-O', 'fwupd.flatpak'] - if 'DEBUG' in os.environ: + dep = 'org.freedesktop.fwupd' + flatpak_dir = os.path.join(os.getenv('HOME'),'.local', 'share', 'flatpak') + verbose = 'DEBUG' in os.environ + + #check if we have installed locally already or not + if not os.path.exists (os.path.join (flatpak_dir, 'app', dep)): + # install into local user's repo + cmd = ['flatpak', 'install', '--user', + 'https://www.flathub.org/repo/appstream/org.freedesktop.fwupd.flatpakref', '--no-deps', '-y'] + if verbose: + print(cmd) + subprocess.run (cmd, cwd=directory, check=True) + + # generate a bundle + repo = os.path.join(flatpak_dir, 'repo') + cmd = ['flatpak', 'build-bundle', repo, 'fwupd.flatpak', dep, 'stable'] + if verbose: print(cmd) subprocess.run (cmd, cwd=directory, check=True) From 137de52927a19e38e33bd0bf4a48e34dfc505235 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 1 Nov 2018 13:35:19 -0500 Subject: [PATCH 049/254] trivial: fu-tool: use `g_variant_unref` instead of `g_object_clear` For dbus call to stop unit. --- src/fu-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index c8eca93b6..b4a823302 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -103,7 +103,7 @@ fu_util_start_engine (FuUtilPrivate *priv, GError **error) SYSTEMD_FWUPD_UNIT, error_local->message); } else { - g_clear_object (&val); + g_variant_unref (val); val = g_dbus_proxy_call_sync (proxy, "StopUnit", g_variant_new ("(ss)", From 67b82af7f8eeab2f3f1cae5f22a3f567f9ab2897 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 1 Nov 2018 13:37:00 -0500 Subject: [PATCH 050/254] trivial: fu-tool: Try to stop systemd even if not compiled with systemd This allows the flatpak (which is compiled without systemd) to be able to stop the running system daemon. --- src/fu-tool.c | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index b4a823302..5cc423d12 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -70,7 +70,6 @@ fu_util_item_free (FuUtilItem *item) static gboolean fu_util_start_engine (FuUtilPrivate *priv, GError **error) { -#ifdef HAVE_SYSTEMD g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GDBusProxy) proxy = NULL; g_autoptr(GVariant) val = NULL; @@ -87,37 +86,40 @@ fu_util_start_engine (FuUtilPrivate *priv, GError **error) SYSTEMD_OBJECT_PATH, SYSTEMD_MANAGER_INTERFACE, NULL, - error); - if (proxy == NULL) - return FALSE; - val = g_dbus_proxy_call_sync (proxy, - "GetUnit", - g_variant_new ("(s)", - SYSTEMD_FWUPD_UNIT), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error_local); - if (val == NULL) { - g_debug ("Unable to find %s: %s", - SYSTEMD_FWUPD_UNIT, + &error_local); + if (proxy == NULL) { + g_debug ("Failed to find %s: %s", + SYSTEMD_SERVICE, error_local->message); } else { - g_variant_unref (val); val = g_dbus_proxy_call_sync (proxy, - "StopUnit", - g_variant_new ("(ss)", - SYSTEMD_FWUPD_UNIT, - "replace"), + "GetUnit", + g_variant_new ("(s)", + SYSTEMD_FWUPD_UNIT), G_DBUS_CALL_FLAGS_NONE, -1, NULL, - error); - if (val == NULL) - return FALSE; + &error_local); + if (val == NULL) { + g_debug ("Unable to find %s: %s", + SYSTEMD_FWUPD_UNIT, + error_local->message); + } else { + g_variant_unref (val); + val = g_dbus_proxy_call_sync (proxy, + "StopUnit", + g_variant_new ("(ss)", + SYSTEMD_FWUPD_UNIT, + "replace"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); + if (val == NULL) + return FALSE; + } } -#endif return fu_engine_load (priv->engine, error); } From 732d641bdc162af6326cb961891d1196fa1ca9da Mon Sep 17 00:00:00 2001 From: RyanChang Date: Mon, 29 Oct 2018 18:37:10 +0800 Subject: [PATCH 051/254] synapticsmst: Access Board ID through memory instead In firmware images HDCP 2.2 will be enabled by default,so access to flash region will fail. --- plugins/synapticsmst/synapticsmst-common.h | 3 +++ plugins/synapticsmst/synapticsmst-device.c | 10 ++++++---- plugins/synapticsmst/synapticsmst.quirk | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/plugins/synapticsmst/synapticsmst-common.h b/plugins/synapticsmst/synapticsmst-common.h index 329e81822..4d1d6076e 100644 --- a/plugins/synapticsmst/synapticsmst-common.h +++ b/plugins/synapticsmst/synapticsmst-common.h @@ -14,6 +14,9 @@ #define ADDR_CUSTOMER_ID 0X10E #define ADDR_BOARD_ID 0x10F +#define ADDR_MEMORY_CUSTOMER_ID 0x170E +#define ADDR_MEMORY_BOARD_ID 0x170F + #define REG_RC_CAP 0x4B0 #define REG_RC_STATE 0X4B1 #define REG_RC_CMD 0x4B2 diff --git a/plugins/synapticsmst/synapticsmst-device.c b/plugins/synapticsmst/synapticsmst-device.c index 53e79bc2a..cffade879 100644 --- a/plugins/synapticsmst/synapticsmst-device.c +++ b/plugins/synapticsmst/synapticsmst-device.c @@ -300,11 +300,13 @@ synapticsmst_device_read_board_id (SynapticsMSTDevice *device, } close (fd); } else { + /* get board ID via MCU address 0x170E instead of flash access due to HDCP2.2 running */ if (!synapticsmst_common_rc_get_command (connection, - UPDC_READ_FROM_EEPROM, - 2, ADDR_CUSTOMER_ID, byte, - error)) { - g_prefix_error (error, "failed ot read EEPROM: "); + UPDC_READ_FROM_MEMORY, + 2, + (gint)ADDR_MEMORY_CUSTOMER_ID, byte, + error)) { + g_prefix_error (error, "Memory query failed: "); return FALSE; } } diff --git a/plugins/synapticsmst/synapticsmst.quirk b/plugins/synapticsmst/synapticsmst.quirk index 75a25f46b..25b3bf354 100644 --- a/plugins/synapticsmst/synapticsmst.quirk +++ b/plugins/synapticsmst/synapticsmst.quirk @@ -15,7 +15,7 @@ # To override this behavior add the custom flag "skip-restart" # -[SynapticsMSTBoardID=0] +[SynapticsMSTBoardID=2] Name = Synaptics EVB development board DeviceKind = evb From da4049499e360be6d7db62d8906b6662c28ffe24 Mon Sep 17 00:00:00 2001 From: RyanChang Date: Fri, 2 Nov 2018 17:59:33 +0800 Subject: [PATCH 052/254] synapticsmst: Remove the content checking of firmware Keep the length checking and remove content checking because don't want to reveal detail format. --- plugins/synapticsmst/synapticsmst-device.c | 119 +-------------------- 1 file changed, 2 insertions(+), 117 deletions(-) diff --git a/plugins/synapticsmst/synapticsmst-device.c b/plugins/synapticsmst/synapticsmst-device.c index cffade879..57d8516bd 100644 --- a/plugins/synapticsmst/synapticsmst-device.c +++ b/plugins/synapticsmst/synapticsmst-device.c @@ -992,11 +992,7 @@ synapticsmst_device_check_firmware_content (SynapticsMSTDevice *device, SynapticsMSTChipKind chip_type, GError **error) { - const guint8 *payload_data; gsize payload_len, payload_len_max; - gint checksum = 0; - guint32 offset = 0; - guint32 code_size = 0; switch (chip_type) { case SYNAPTICSMST_CHIP_KIND_PANAMERA: @@ -1015,8 +1011,8 @@ synapticsmst_device_check_firmware_content (SynapticsMSTDevice *device, } - /* get firmware data and check size */ - payload_data = g_bytes_get_data (fw, &payload_len); + /* check size */ + payload_len = g_bytes_get_size (fw); if (payload_len > payload_len_max || payload_len == 0) { g_set_error (error, G_IO_ERROR, @@ -1027,117 +1023,6 @@ synapticsmst_device_check_firmware_content (SynapticsMSTDevice *device, return FALSE; } - /* check firmware content */ - for (guint8 i = 0; i < 128; i++) - checksum += *(payload_data + i); - if (checksum & 0xff) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "EDID checksum error: %d", - checksum); - return FALSE; - } - /* EDID */ - checksum = 0; - offset = 128; - for (guint8 i = 0; i < 128; i++) - checksum += *(payload_data + offset + i); - - if (checksum & 0xff) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "EDID checksum error"); - return FALSE; - } - /* CFG 0 */ - checksum = 0; - offset = 0x100; - for (guint16 i = 0; i < 256; i++) - checksum += *(payload_data + offset + i); - - if (checksum & 0xff) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "configuration checksum error"); - return FALSE; - } - /* CFG 1 */ - checksum = 0; - offset = 0x200; - for (guint16 i = 0; i < 256; i++) - checksum += *(payload_data + offset + i); - if (checksum & 0xff) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "configuration checksum error"); - return FALSE; - } - /* Firmware Size */ - checksum = 0; - offset = 0x400; - if (chip_type == SYNAPTICSMST_CHIP_KIND_PANAMERA) { - code_size = (*(payload_data + offset) << 24); - code_size += (*(payload_data + offset + 1) << 16); - code_size += (*(payload_data + offset + 2) << 8); - code_size += (*(payload_data + offset + 3)); - if (code_size >= 0x02ffff) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid firmware size"); - return FALSE; - } - } else { - code_size = (*(payload_data + offset) << 8) + *(payload_data + offset + 1); - if (code_size >= 0xffff) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid firmware size"); - return FALSE; - } - } - /* Firmware Checksum */ - if (chip_type == SYNAPTICSMST_CHIP_KIND_PANAMERA) { - guint32 i = 0; - for ( i = 0; i < code_size + 1; i++ ) { - checksum += *(payload_data + offset + 0x10 + i); - } - if ((checksum & 0xffff)!=((*(payload_data + 0x408) << 8) | (*(payload_data + 0x409)))) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware checksum error"); - return FALSE; - } - checksum = 0; - offset = EEPROM_ESM_OFFSET; - for (i = 0; i < (payload_len - EEPROM_ESM_OFFSET); i++) { - checksum += *(payload_data + offset + i); - } - if ((checksum & 0xffff)!=((*(payload_data + 0x40A) << 8) | (*(payload_data + 0x40B)))) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "ESM firmware checksum error"); - return FALSE; - } - } else { - for (guint32 i = 0; i < (code_size + 17); i++) - checksum += *(payload_data + offset + i); - - if (checksum & 0xff) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware checksum error"); - return FALSE; - } - } return TRUE; } From 5e36c9e792e6c28e412364c0ec6e7b392b090523 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 5 Nov 2018 08:17:51 -0600 Subject: [PATCH 053/254] synapticsmst: Adjust EVB board handling 1. Since board ID in synapticsmst.quirk is different based upon how the board ID is read, don't whitelist it in `write_firmware` 2. Allow using `--force` with `fwupdmgr` or `fwupdtool` to override board ID check. 3. Allow using custom flag `ignore-board-id` to ignore board IDs. This will be the default for EVB boards and can be used in the event of a factory mistake as well. 4. Move the EVB board IDs into their own synapticsmst_evb.quirk. This file will not be installed by default (So EVB boards are only functional when manually installed). --- plugins/synapticsmst/fu-plugin-synapticsmst.c | 4 ++++ plugins/synapticsmst/synapticsmst-device.c | 20 ++++++++----------- plugins/synapticsmst/synapticsmst-device.h | 1 + plugins/synapticsmst/synapticsmst.quirk | 4 ---- plugins/synapticsmst/synapticsmst_evb.quirk | 18 +++++++++++++++++ 5 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 plugins/synapticsmst/synapticsmst_evb.quirk diff --git a/plugins/synapticsmst/fu-plugin-synapticsmst.c b/plugins/synapticsmst/fu-plugin-synapticsmst.c index 83c9eee93..780064834 100644 --- a/plugins/synapticsmst/fu-plugin-synapticsmst.c +++ b/plugins/synapticsmst/fu-plugin-synapticsmst.c @@ -340,6 +340,7 @@ fu_plugin_update (FuPlugin *plugin, guint8 layer; guint8 rad; gboolean reboot; + gboolean install_force; /* extract details to build a new device */ kind = synapticsmst_device_kind_from_string (fu_device_get_metadata (dev, "SynapticsMSTKind")); @@ -359,11 +360,14 @@ fu_plugin_update (FuPlugin *plugin, if (!synapticsmst_device_enumerate_device (device, error)) return FALSE; reboot = !fu_device_has_custom_flag (dev, "skip-restart"); + install_force = (flags & FWUPD_INSTALL_FLAG_FORCE) != 0 || + fu_device_has_custom_flag (dev, "ignore-board-id"); fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); if (!synapticsmst_device_write_firmware (device, blob_fw, fu_synapticsmst_write_progress_cb, dev, reboot, + install_force, error)) { g_prefix_error (error, "failed to flash firmware: "); return FALSE; diff --git a/plugins/synapticsmst/synapticsmst-device.c b/plugins/synapticsmst/synapticsmst-device.c index 57d8516bd..3598abfa1 100644 --- a/plugins/synapticsmst/synapticsmst-device.c +++ b/plugins/synapticsmst/synapticsmst-device.c @@ -1117,6 +1117,7 @@ synapticsmst_device_write_firmware (SynapticsMSTDevice *device, GFileProgressCallback progress_cb, gpointer progress_data, gboolean reboot, + gboolean install_force, GError **error) { const guint8 *payload_data; @@ -1137,21 +1138,16 @@ synapticsmst_device_write_firmware (SynapticsMSTDevice *device, return FALSE; } - /* TODO: May need a way to override this to cover field - * issues of invalid firmware flashed*/ /* check firmware and board ID again */ tmp = (*(payload_data + ADDR_CUSTOMER_ID) << 8) + *(payload_data + ADDR_BOARD_ID); - if (synapticsmst_device_get_board_id (device) >> 8 == 0) { - g_warning ("EVB board detected, bypassing customer ID check"); - } else { - if (tmp != synapticsmst_device_get_board_id (device)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "board ID mismatch"); - return FALSE; - } + if (tmp != synapticsmst_device_get_board_id (device) && !install_force) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "board ID mismatch"); + return FALSE; } + /* open device */ if (!synapticsmst_device_open (device, error)) { g_prefix_error (error, diff --git a/plugins/synapticsmst/synapticsmst-device.h b/plugins/synapticsmst/synapticsmst-device.h index e0cdecb77..c3bc4a579 100644 --- a/plugins/synapticsmst/synapticsmst-device.h +++ b/plugins/synapticsmst/synapticsmst-device.h @@ -82,6 +82,7 @@ gboolean synapticsmst_device_write_firmware (SynapticsMSTDevice *device, GFileProgressCallback progress_cb, gpointer user_data, gboolean reboot, + gboolean install_force, GError **error); G_END_DECLS diff --git a/plugins/synapticsmst/synapticsmst.quirk b/plugins/synapticsmst/synapticsmst.quirk index 25b3bf354..6a5c8ad2e 100644 --- a/plugins/synapticsmst/synapticsmst.quirk +++ b/plugins/synapticsmst/synapticsmst.quirk @@ -15,10 +15,6 @@ # To override this behavior add the custom flag "skip-restart" # -[SynapticsMSTBoardID=2] -Name = Synaptics EVB development board -DeviceKind = evb - [SynapticsMSTBoardID=272] Name = Dell X6 Platform DeviceKind = system diff --git a/plugins/synapticsmst/synapticsmst_evb.quirk b/plugins/synapticsmst/synapticsmst_evb.quirk new file mode 100644 index 000000000..209e7c7ac --- /dev/null +++ b/plugins/synapticsmst/synapticsmst_evb.quirk @@ -0,0 +1,18 @@ +# Synaptics MST early validation board support +# +# This is not installed by default, but can be used to exercise new boards +# that don't yet have customer ID or board ID bytes filled out. +# +# To use it, load the quirk file into the quirks directory for the fwupd installation +# Usually this is /usr/share/fwupd/quirks.d +# +# Note: The flag "ignore-board-id" will be used to ignore the board ID checking in +# during flashing. This shouldn't be used in practice for production boards. +# + +[SynapticsMSTBoardID=2] +Name = Synaptics EVB development board +DeviceKind = panamera_evb + +[Guid=MST-panamera_evb-vmm5331-2] +Flags = ignore-board-id From b095df6d4d199605e02c90a2e7f495dced17cdb0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Nov 2018 11:41:36 +0000 Subject: [PATCH 054/254] trivial: Fix some NULL/FALSE confusion --- src/fu-engine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index bbf1bdf03..b2b6e642d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2483,10 +2483,10 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "No releases found for device"); - return FALSE; + return NULL; } g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; + return NULL; } /* find all the releases that pass all the requirements */ From 777fabf033dffd29daa7cc225a3d72e06a76cb72 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 5 Nov 2018 09:59:35 -0600 Subject: [PATCH 055/254] dell-dock: Drop delayed MST callback routine Since dell_dock is the priority plugin for MST flashing the VMM5331 no need to do delayed callbacks anymore. When the dell_dock plugin bumps to EC 15 being the minimum requirement more code can also be dropped. --- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 57 ++++-------------------- 1 file changed, 9 insertions(+), 48 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index a57e66bad..6f93c80a0 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -105,7 +105,6 @@ struct _FuDellDockMst { FuDevice parent_instance; FuDevice *symbiote; guint8 unlock_target; - guint relock_id; guint64 blob_major_offset; guint64 blob_minor_offset; guint64 blob_build_offset; @@ -781,16 +780,6 @@ fu_dell_dock_mst_write_fw (FuDevice *device, g_return_val_if_fail (blob_fw != NULL, FALSE); g_return_val_if_fail (self->symbiote != NULL, FALSE); - /* in case update was scheduled immediately after setup */ - if (self->relock_id > 0) { - g_source_remove (self->relock_id); - self->relock_id = 0; - } - - /* power up controller in case it's asleep */ - if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) - return FALSE; - dynamic_version = g_strdup_printf ("%02x.%02x.%02x", data[self->blob_major_offset], data[self->blob_minor_offset], @@ -928,26 +917,6 @@ fu_dell_dock_mst_set_quirk_kv (FuDevice *device, return FALSE; } -static gboolean -fu_dell_dock_mst_relock (gpointer user_data) -{ - FuDellDockMst *self = (FuDellDockMst *) user_data; - FuDevice *device = FU_DEVICE (self); - g_autoptr(GError) error_local = NULL; - gboolean ret; - - self->relock_id = 0; - g_debug ("MST relock called"); - /* only call if parent still around */ - if (fu_device_get_parent (device) != NULL) { - ret = fu_dell_dock_set_power (device, self->unlock_target, - FALSE, &error_local); - if (!ret) - g_warning ("%s", error_local->message); - } - return G_SOURCE_REMOVE; -} - static gboolean fu_dell_dock_mst_setup (FuDevice *device, GError **error) { @@ -956,15 +925,6 @@ fu_dell_dock_mst_setup (FuDevice *device, GError **error) const gchar *version; g_autofree gchar *dynamic_version = NULL; - /* Open up access to the controller - * - This is left open with a timeout to allow DP aux to initialize - * - This intentionally isn't called in open, it should be called by - * plugin during update - */ - if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) - return FALSE; - self->relock_id = g_timeout_add (6000, fu_dell_dock_mst_relock, self); - /* sanity check that we can talk to MST */ if (!fu_d19_mst_check_fw (self->symbiote, error)) return FALSE; @@ -973,9 +933,7 @@ fu_dell_dock_mst_setup (FuDevice *device, GError **error) parent = fu_device_get_parent (device); version = fu_dell_dock_ec_get_mst_version (parent); - /* TODO: Potentially remove direct probe if we know EC return correct - * value at all times - */ + /* TODO: Drop when we can guarantee EC 15+ */ if (version == NULL) { if (!fu_dell_dock_mst_get_version_direct (self->symbiote, &dynamic_version, @@ -1013,6 +971,10 @@ fu_dell_dock_mst_open (FuDevice *device, GError **error) if (!fu_device_open (self->symbiote, error)) return FALSE; + /* open up access to controller bus */ + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + return TRUE; } @@ -1021,6 +983,10 @@ fu_dell_dock_mst_close (FuDevice *device, GError **error) { FuDellDockMst *self = FU_DELL_DOCK_MST (device); + /* close access to controller bus */ + if (!fu_dell_dock_set_power (device, self->unlock_target, FALSE, error)) + return FALSE; + return fu_device_close (self->symbiote, error); } @@ -1028,11 +994,6 @@ static void fu_dell_dock_mst_finalize (GObject *object) { FuDellDockMst *self = FU_DELL_DOCK_MST (object); - if (self->relock_id > 0) { - g_source_remove (self->relock_id); - self->relock_id = 0; - fu_dell_dock_mst_relock (self); - } g_object_unref (self->symbiote); G_OBJECT_CLASS (fu_dell_dock_mst_parent_class)->finalize (object); } From 9e21daaef4e1fe219f13b5f8b443b894d91b5a56 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Wed, 7 Nov 2018 11:30:46 +0100 Subject: [PATCH 056/254] ebitdo: remove SF30/SN30 pro device ids The ids clash with the Xbox controller ids. This makes the Xbox controller unusable since fwupd unloads the device just after connecting it and fails to update it not being a 8bitdo device. As seen here: https://github.com/paroj/xpad/issues/114 --- plugins/ebitdo/ebitdo.quirk | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/ebitdo/ebitdo.quirk b/plugins/ebitdo/ebitdo.quirk index be6bd9e4c..bf39badf4 100644 --- a/plugins/ebitdo/ebitdo.quirk +++ b/plugins/ebitdo/ebitdo.quirk @@ -70,7 +70,3 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_6001] Plugin = ebitdo Flags = none -## Xinput mode (Start + X) -[DeviceInstanceId=USB\VID_045E&PID_028E] -Plugin = ebitdo -Flags = none From aaa60c60d92358c954cc314d4f359ba22859afc1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Nov 2018 11:05:50 +0000 Subject: [PATCH 057/254] trivial: Fix a typo in the verification store export --- src/fu-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index b2b6e642d..d9af7773e 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -604,7 +604,7 @@ fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error) const gchar *checksum = g_ptr_array_index (checksums, i); GChecksumType kind = fwupd_checksum_guess_kind (checksum); g_autoptr(XbBuilderNode) csum = NULL; - csum = xb_builder_node_insert (provides, "checksum", + csum = xb_builder_node_insert (release, "checksum", "type", fu_engine_checksum_type_to_string (kind), "target", "content", NULL); From be95da483ca69263a1013d498b439134d678d3e3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Nov 2018 11:13:23 +0000 Subject: [PATCH 058/254] trivial: Fix some NULL/FALSE confusion --- src/fu-common-cab.c | 2 +- src/fu-common-guid.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fu-common-cab.c b/src/fu-common-cab.c index 7dee87959..c755b9b05 100644 --- a/src/fu-common-cab.c +++ b/src/fu-common-cab.c @@ -398,7 +398,7 @@ fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) FWUPD_ERROR_INTERNAL, "failed to create temp dir: %s", error_local->message); - return FALSE; + return NULL; } helper.decompress_path = tmp_path; tmp_file = g_file_new_for_path (tmp_path); diff --git a/src/fu-common-guid.c b/src/fu-common-guid.c index fe9006604..6adfeea96 100644 --- a/src/fu-common-guid.c +++ b/src/fu-common-guid.c @@ -46,9 +46,9 @@ fu_common_guid_from_data (const gchar *namespace_id, uuid_t uu_new; g_autoptr(GChecksum) csum = NULL; - g_return_val_if_fail (namespace_id != NULL, FALSE); - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data_len != 0, FALSE); + g_return_val_if_fail (namespace_id != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (data_len != 0, NULL); /* convert the namespace to binary */ rc = uuid_parse (namespace_id, uu_namespace); @@ -58,7 +58,7 @@ fu_common_guid_from_data (const gchar *namespace_id, FWUPD_ERROR_NOT_SUPPORTED, "namespace '%s' is invalid", namespace_id); - return FALSE; + return NULL; } /* hash the namespace and then the string */ From 2a172e8dd2a9ccb7662be60c6a355f5286eac054 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Nov 2018 11:20:39 +0000 Subject: [PATCH 059/254] Release fwupd 1.2.0 --- NEWS | 30 ++++ po/LINGUAS | 1 + po/ast.po | 4 +- po/ca.po | 57 +++++- po/cs.po | 386 ++++++++++++++++++++++++++++++++++++--- po/de.po | 506 ++++++++++++++++++++++++++++++++++++++++++++++++++-- po/en_GB.po | 4 +- po/fi.po | 4 +- po/fr.po | 4 +- po/fur.po | 4 +- po/he.po | 4 +- po/hi.po | 4 +- po/hr.po | 4 +- po/hu.po | 6 +- po/id.po | 4 +- po/it.po | 57 +++++- po/ko.po | 4 +- po/ky.po | 73 ++++++++ po/nl.po | 4 +- po/oc.po | 4 +- po/pl.po | 59 +++++- po/pt_BR.po | 14 +- po/ru.po | 4 +- po/sk.po | 4 +- po/sr.po | 4 +- po/sv.po | 6 +- po/tr.po | 4 +- po/uk.po | 59 +++++- po/zh_CN.po | 4 +- po/zh_TW.po | 206 ++++++++++++++++++++- 30 files changed, 1386 insertions(+), 142 deletions(-) create mode 100644 po/ky.po diff --git a/NEWS b/NEWS index f461e7212..4e73c4758 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,33 @@ +Version 1.2.0 +~~~~~~~~~~~~~ +Released: 2018-11-07 + +New Features: + - Add a plugin for an upcoming Dell USB-C dock (Mario Limonciello) + - Add a standalone installer creation script (Mario Limonciello) + - Add support for devices to show an estimated flash time (Mario Limonciello) + - Add support for some new Realtek USB devices (Richard Hughes) + - Allow firmware files to depend on versions from other devices (Richard Hughes) + - Allow setting the version format from a quirk entry (Richard Hughes) + - Port from libappstream-glib to libxmlb for a large reduction in RSS (Richard Hughes) + - Stop any running daemon over dbus when using fu-tool (Mario Limonciello) + - Support the Intel ME version format (Richard Hughes) + +Bugfixes: + - Add version format quirks for several Lenovo machines (Richard Hughes) + - Adjust panamera ESM update routine for some reported issues (Mario Limonciello) + - Adjust synapticsmst EVB board handling (Mario Limonciello, RyanChang) + - Check the amount of free space on the ESP (Richard Hughes) + - Don't show devices pending a reboot in GetUpgrades (Mario Limonciello) + - Ensure that parent ID is created before creating quirked children (Mario Limonciello) + - Optionally wait for replug before updating a device (Mario Limonciello) + - Set the full AMT device version including the BuildNum (Richard Hughes) + - Sort the firmware sack by component priority (Richard Hughes) + - Stop showing errors when no Dell dock plugged in (Mario Limonciello) + - Stop showing the current release during updates in fwupdmgr (Mario Limonciello) + - Update all sub-devices for a composite update (Mario Limonciello) + - Use HTTPS_PROXY if set (Richard Hughes) + Version 1.1.2 ~~~~~~~~~~~~~ Released: 2018-09-10 diff --git a/po/LINGUAS b/po/LINGUAS index 82e037864..c96395e31 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -15,6 +15,7 @@ id it kk ko +ky nl oc pl diff --git a/po/ast.po b/po/ast.po index ab2963291..772e32680 100644 --- a/po/ast.po +++ b/po/ast.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Asturian (http://www.transifex.com/freedesktop/fwupd/language/ast/)\n" "MIME-Version: 1.0\n" diff --git a/po/ca.po b/po/ca.po index 16afe4514..a2af6138b 100644 --- a/po/ca.po +++ b/po/ca.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-10 16:44+0100\n" -"PO-Revision-Date: 2018-09-10 15:45+0000\n" -"Last-Translator: Richard Hughes \n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 12:35+0000\n" +"Last-Translator: Antoni Bella Pérez \n" "Language-Team: Catalan (http://www.transifex.com/freedesktop/fwupd/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +19,13 @@ msgstr "" "Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Manca %.0f minut" +msgstr[1] "Manquen %.0f minuts" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" @@ -260,10 +267,10 @@ msgstr "Desactualitza el microprogramari en un dispositiu" msgid "Downgrading %s from %s to %s... " msgstr "S'està desactualitzant %s des de %s a %s... " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s…" -msgstr "S'està desactualitzant %s des de la %s a la %s…" +msgid "Downgrading %s…" +msgstr "S'està desactualitzant %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -396,6 +403,9 @@ msgstr "Les actualitzacions de microprogramari no estan admeses en aquesta màqu msgid "Firmware updates are supported on this machine." msgstr "Les actualitzacions de microprogramari estan admeses en aquesta màquina." +msgid "Force the action ignoring all warnings" +msgstr "Força l'acció ignorant tots els avisos" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "S'ha trobat" @@ -484,9 +494,18 @@ msgstr "S'està instal·lant %s" msgid "Installing firmware update…" msgstr "S'està instal·lant l'actualització de microprogramari..." +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "S'està intal·lant a %s…" + msgid "Keyring" msgstr " Anell de claus" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Manca menys d'un minut" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Servei de microprogramari del proveïdor Linux (microprogramari estable)" @@ -587,6 +606,12 @@ msgstr "Permís denegat" msgid "Please enter a number from 0 to %u: " msgstr "Introduïu un número del 0 al %u: " +msgid "Print the version number" +msgstr "Imprimeix el número de versió" + +msgid "Print verbose debug statements" +msgstr "Imprimeix les sentències detallades de la depuració" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioritat" @@ -733,6 +758,10 @@ msgstr "Comparteix l'historial de microprogramari amb els desenvolupadors" msgid "Show client and daemon versions" msgstr "Mostra les versions del client i el dimoni" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Mostra la informació detallada del dimoni" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostra la informació de depuració per a tots els fitxers" @@ -765,6 +794,12 @@ msgstr "Mostra el registre de depuració del darrer intent d'actualització" msgid "Show the information of firmware update status" msgstr "Mostra la informació sobre l'estat de l'actualització del microprogramari" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifiqueu el proveïdor/ID del producte del dispositiu DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifiqueu el nombre de bytes per a la transferència USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Estat" @@ -789,6 +824,10 @@ msgstr "El LVFS és un servei gratuït que funciona com una entitat legal indepe msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." msgstr "El procés del «fwupd» és un dimoni senzill, el qual permet que una sessió de programari actualitzi el microprogramari del dispositiu a la màquina local. Està dissenyat per a equips d'escriptori, però aquest projecte també és usable a telèfons, tauletes i servidors sense perifèrics." +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "L'actualització requereix un reinici per a completar-se." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Aquest programa només pot funcionar correctament com a «root»" @@ -891,10 +930,10 @@ msgstr "Actualitza tot el microprogramari a les versions més recents" msgid "Updating %s from %s to %s... " msgstr "S'està actualitzant %s des de %s a %s... " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s…" -msgstr "S'està actualitzant %s des de la %s a la %s…" +msgid "Updating %s…" +msgstr "S'està actualitzant %s…" #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" diff --git a/po/cs.po b/po/cs.po index 90a69e8a2..5554e9aac 100644 --- a/po/cs.po +++ b/po/cs.po @@ -3,15 +3,15 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Daniel Rusek , 2017 -# Daniel Rusek , 2017 -# Marek Černocký , 2016 +# Ascii Wolf , 2017 +# Ascii Wolf , 2017 +# Marek Černocký , 2016,2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Czech (http://www.transifex.com/freedesktop/fwupd/language/cs/)\n" "MIME-Version: 1.0\n" @@ -20,6 +20,15 @@ msgstr "" "Language: cs\n" "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Zbývá %.0f minuta" +msgstr[1] "Zbývají %.0f minuty" +msgstr[2] "Zbývá %.0f minut" +msgstr[3] "Zbývá %.0f minuty" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" @@ -31,7 +40,11 @@ msgstr "Přidáno" #. TRANSLATORS: the age of the metadata msgid "Age" -msgstr "Věk" +msgstr "Stáří" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Odsouhlasit a povolit vzdálený zdroj?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format @@ -40,35 +53,56 @@ msgstr "Alias pro %s" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" -msgstr "Povolit ponížení verze firmwaru" +msgstr "Povolit přechod na nižší verze firmwaru" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Povolit reinstalaci stávající verze firmwaru" +#. TRANSLATORS: explain why we want to upload +msgid "An update requires a reboot to complete." +msgstr "Některá z aktualizací vyžaduje pro dokončení restart." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Na všechny dotazy odpovědět ano" + #. TRANSLATORS: command description msgid "Apply a binary patch" msgstr "Použít binární záplatu" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Použít aktualizace firmwaru" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" -msgstr "Napojit zařízení podporující DFU zpět do běhového režimu" +msgstr "Napojit zařízení podporující DFU zpět do provozního režimu" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Napojit do režimu firmwaru" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Vlastnosti" #. TRANSLATORS: waiting for user to authenticate msgid "Authenticating…" -msgstr "Ověřuje se…" +msgstr "Autentizuje se…" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "K ponížení verze firmwaru na výměnném zařízení je vyžadováno ověření" +msgstr "K přechodu na nižší verzi firmwaru na výměnném zařízení je vyžadováno ověření" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "K ponížení verze firmwaru na tomto počítači je vyžadováno ověření" +msgstr "K přechodu na nižší verzi firmwaru na tomto počítači je vyžadováno ověření" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify a configured remote used for firmware updates" -msgstr "K úpravě nastaveného vzdáleného zdroje používaného pro aktualizace firmwaru je vyžadováno ověření" +msgstr "Ke změně nastaveného vzdáleného zdroje, který se používá pro aktualizace firmwaru, je vyžadováno ověření" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" @@ -90,6 +124,10 @@ msgstr "K aktualizaci uložených kontrolních součtů zařízení je vyžadov msgid "Build firmware using a sandbox" msgstr "Sestavit firmware za použití izolovaného prostředí" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Zrušit" + #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" msgstr "Zrušeno" @@ -104,6 +142,10 @@ msgstr "Změněno" msgid "Checksum" msgstr "Kontrolní součet" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ID čipu" + #. TRANSLATORS: get interactive prompt msgid "Choose a device:" msgstr "Vyberte zařízení:" @@ -118,7 +160,7 @@ msgstr "Šifra" #. TRANSLATORS: command description msgid "Clears any updates scheduled to be updated offline" -msgstr "Smazat všechny aktualizace naplánované pro offline aktualizaci" +msgstr "Smazat vše naplánované pro aktualizaci při odpojení" #. TRANSLATORS: command description msgid "Clears the results from the last update" @@ -136,6 +178,9 @@ msgstr "Převést firmware do formátu DFU" msgid "Create a binary patch using two files" msgstr "Vytvořit binární záplatu za použití dvou souborů" +msgid "DFU" +msgstr "DFU" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" msgstr "Nástroj pro práci s DFU" @@ -146,7 +191,7 @@ msgstr "Volby ladění" #. TRANSLATORS: decompressing the firmware file msgid "Decompressing…" -msgstr "Rozbaluje se firmware…" +msgstr "Rozbaluje se…" #. TRANSLATORS: command description msgid "Decrypt firmware data" @@ -160,6 +205,10 @@ msgstr "Popis" msgid "Detach currently attached DFU capable device" msgstr "Odpojit aktuálně napojené zařízení podporující DFU" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Odpojit do režimu zavaděče" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Přidáno zařízení:" @@ -172,19 +221,54 @@ msgstr "Změněno zařízení:" msgid "Device removed:" msgstr "Odebráno zařízení:" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Zařízení, která byla úspěšně aktualizována:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Zařízení, která nebyla úspěšně aktualizována:" + +msgid "Disabled fwupdate debugging" +msgstr "Vypnout ladění fwupdate" + +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "Zakázat zadaný vzdálený zdroj" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Zobrazit verzi" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Nekontrolovat stáří metadat" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Nekontrolovat restart po aktualizaci" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Nekontrolovat nenahlášení historie" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Nezapisovat do databáze historie" + msgid "Done!" msgstr "Hotovo!" #. TRANSLATORS: command description msgid "Downgrades the firmware on a device" -msgstr "Ponížit verzi firmwaru na zařízení" +msgstr "Přejít na nižší verzi firmwaru na zařízení" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" #, c-format msgid "Downgrading %s from %s to %s... " -msgstr "Ponižuje se %s z verze %s na %s…" +msgstr "Převádí se %s z verze %s na %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -192,7 +276,7 @@ msgstr "Stahuje se…" #. TRANSLATORS: command description msgid "Dump SMBIOS data from a file" -msgstr "Vypsat SMBIOS data ze souboru" +msgstr "Vypsat data SMBIOS ze souboru" #. TRANSLATORS: command description msgid "Dump details about a firmware file" @@ -202,14 +286,44 @@ msgstr "Vypsat podrobnosti o souboru s firmwarem" msgid "Dump information about a binary patch to the screen" msgstr "Vypsat na obrazovku informace o binární záplatě" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Určený ESP není platný" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Povolit podporu aktualizace firmwaru na podporovaných systémech" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Povolit tento vzdálený zdroj?" + #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Povoleno" +msgid "Enabled fwupdate debugging" +msgstr "Zapnout ladění fwupdate" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Povolit zadaný vzdálený zdroj" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Zapnutí této funkcionality je na vaše vlastní riziko, což znamená, že v případě problémů způsobených aktualizací musíte kontaktovat přímo výrobce zařízení. Pouze problémy s aktualizačním procesem jako takovým by měly být hlášeny na $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Povolení tohoto zdroje je na vaše vlastní riziko." + #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Zašifrovat data firmwaru" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Smazat veškerou historii aktualizací" + #. TRANSLATORS: erasing contents of the flash chips msgid "Erasing…" msgstr "Maže se…" @@ -222,6 +336,14 @@ msgstr "Skončit po krátké prodlevě" msgid "Exit after the engine has loaded" msgstr "Skončit po načtení výkonné části" +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Nezdařilo se stáhnout kvůli omezením serveru" + +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Selhalo načtení zvláštních požadavků" + #. TRANSLATORS: the user didn't read the man page msgid "Failed to parse arguments" msgstr "Selhalo zpracování argumentů" @@ -266,6 +388,21 @@ msgstr "Démon pro aktualizaci firmwaru" msgid "Firmware Utility" msgstr "Nástroj pro práci s firmwarem" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Metadata firmwaru nebyla akualizována již celý den a nelze je aktualizovat." +msgstr[1] "Metadata firmwaru nebyla akualizována již %u dny a nelze je aktualizovat." +msgstr[2] "Metadata firmwaru nebyla akualizována již %u dní a nelze je aktualizovat." +msgstr[3] "Metadata firmwaru nebyla akualizována již %u dne a nelze je aktualizovat." + +msgid "Firmware updates are not supported on this machine." +msgstr "Aktualizace firmwaru nejsou na tomto počítači podporované." + +msgid "Firmware updates are supported on this machine." +msgstr "Aktualizace firmwaru jsou na tomto počítači podporované." + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Nalezeno" @@ -273,13 +410,21 @@ msgstr "Nalezeno" msgid "GUID" msgstr "GUID" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Zjistit všechna zařízení podle topologie systému" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Zjistit všechna zařízení podporující aktualizaci firmwaru" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Zjistit všechny povolené zásuvné moduly registrované v systému" + #. TRANSLATORS: command description msgid "Gets details about a firmware file" -msgstr "Vypsat podrobnosti o souboru s firmwarem" +msgstr "Zjistit podrobnosti o souboru s firmwarem" #. TRANSLATORS: command description msgid "Gets the configured remotes" @@ -309,6 +454,10 @@ msgstr "ID" msgid "Idle…" msgstr "Nečinný…" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Nainstalovat na zařízení binární soubor s firmwarem" + #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Nainstalovat soubor s firmwarem na tento hardware" @@ -332,21 +481,50 @@ msgstr "Instalace nepodepsaného firmwaru zařízení" msgid "Install unsigned system firmware" msgstr "Instalace nepodepsaného systémového firmwaru" +#. show message in progressbar +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing %s" +msgstr "Instaluje se zařízení %s" + #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instaluje se aktualizace firmwaru…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Instaluje se na zařízení %s…" + msgid "Keyring" msgstr "Klíčenka" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Zbývá méně než jedna minuta" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabilní firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (testovací firmware)" + #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Vypsat právě napojená zařízení podporující DFU" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Vypsat podporované aktualizace firmwarů" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Načítá se…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Ručně povolit konkrétní zásuvné moduly" + #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Sloučit více firmwarů do jednoho" @@ -359,19 +537,23 @@ msgstr "URI metadat" msgid "Metadata URI Signature" msgstr "Podpis URI metadat" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadata lze získat ze služby Linux Vendor Firmware." + msgid "Mode" msgstr "Režim" #. TRANSLATORS: command description msgid "Modifies a given remote" -msgstr "Upraví zadaný vzdálený zdroj" +msgstr "Změnit zadaný vzdálený zdroj" msgid "Modify a configured remote" msgstr "Upravit nastavený vzdálený zdroj" #. TRANSLATORS: command description msgid "Monitor the daemon for events" -msgstr "Sledovat události démonu" +msgstr "Sledovat události démona" #. TRANSLATORS: interface name, e.g. "Flash" #. TRANSLATORS: device name, e.g. 'ColorHug2' @@ -379,11 +561,22 @@ msgstr "Sledovat události démonu" msgid "Name" msgstr "Název" +msgid "No action specified!" +msgstr "Není určena žádné akce!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nebylo nalezeno žádné zařízení schopné aktualizace firmwaru" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nebyl nalezen žádný zásuvný modul" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Zrovna nejsou povolené žádné vzdálené zdroje, takže nejsou k dispozici žádná metadata." + msgid "OK" msgstr "V pořádku" @@ -391,18 +584,40 @@ msgstr "V pořádku" msgid "Override plugin warning" msgstr "Potlačit varování zásuvného modulu" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Přepsat výchozí cestu ESP" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Heslo" +msgid "Payload" +msgstr "Obsah" + +msgid "Permission denied" +msgstr "Byl odepřen přístup" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Zadejte prosím číslo od 0 do %u:" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Priorita" +msgid "Proceed with upload?" +msgstr "Pokračovat v nahrávání?" + #. TRANSLATORS: DFU protocol version, e.g. 1.1 msgid "Protocol" msgstr "Protokol" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Dotázat se na podporu aktualizace firmwaru" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -441,7 +656,7 @@ msgstr "Vzdálený zdroj" #. TRANSLATORS: remote identifier, e.g. lvfs-testing msgid "Remote ID" -msgstr "Vzdálené ID" +msgstr "ID vzdáleného zdroje" #. TRANSLATORS: this is when a device is hotplugged msgid "Removed" @@ -449,7 +664,23 @@ msgstr "Odebráno" #. TRANSLATORS: command description msgid "Replace data in an existing firmware file" -msgstr "Nahradit data v existujícím souboru s firmwarem" +msgstr "Nahradit data ve stávajícím souboru s firmwarem" + +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "URI hlášení" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Vyžaduje připojení k Internetu" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Resetovat zařízení podporující DFU" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Restartovat nyní?" #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device…" @@ -459,6 +690,9 @@ msgstr "Zařízení se restartuje…" msgid "Return all the hardware IDs for the machine" msgstr "Vrátit všechna ID hardwaru počítače" +msgid "Runtime" +msgstr "provozní" + #. TRANSLATORS: command line option msgid "Schedule installation for next reboot when possible" msgstr "Pokud je to možné, naplánovat instalaci na příští restart" @@ -491,6 +725,10 @@ msgstr "Nastavit ID produktu v souboru s firmwarem" msgid "Set release version on firmware file" msgstr "Nastavit verzi vydání v souboru s firmwarem" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Během aktualizace nastavit příznak ladění" + #. TRANSLATORS: command description msgid "Set the firmware size for the target" msgstr "Nastavit velikost firmwaru pro cíl" @@ -503,22 +741,46 @@ msgstr "Nastavit ID výrobce v souboru s firmwarem" msgid "Sets metadata on a firmware file" msgstr "Nastavit metadata v souboru s firmwarem" +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Sdílet historii firmwaru s vývojáři" + #. TRANSLATORS: command line option msgid "Show client and daemon versions" -msgstr "Zobrazit verzi klienta a démonu" +msgstr "Zobrazit verzi klienta a démona" #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" -msgstr "Zobrazovat ladicí informace pro všechny soubory" +msgstr "Zobrazit ladicí informace pro všechny soubory" #. TRANSLATORS: for the --verbose arg msgid "Show debugging options" msgstr "Zobrazit volby ladění" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Zobrazit zařízení, která nelze aktualizovat" + #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Zobrazovat doplňující informace pro ladění" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Zobrazit historii aktualizací firmwaru" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Zobrazit podrobné informace o zásuvném modulu" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Zobrazit ladicí záznam z posledního pokusu o aktualizaci" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Zobrazit informace o stavu aktualizace firmwaru" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stav" @@ -529,11 +791,33 @@ msgstr "Stav" msgid "Status" msgstr "Stav" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Souhrn" + +msgid "Target" +msgstr "Cíl" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." + msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Proces fwupd je jednoduchý démon, který umožňuje softwaru sezení aktualizovat firmware zařízení na vašem počítači. Je navržen pro stolní počítače, ale je možno jej použít také na telefonech, tabletech a serverech bez monitoru." +msgstr "Proces fwupd je jednoduchý démon, který umožňuje softwaru sezení aktualizovat firmware zařízení na vašem počítači. Je navržen pro stolní počítače, ale je možné jej používat i na telefonech, tabletech a serverech bez monitoru." + +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "Pro dokončení aktualizace je potřeba provést restart." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Tento program může správně fungovat jen pod uživatelem root" msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Cílem tohoto projektu je učinit aktualizaci firmwaru na Linuxu automatickou, bezpečnou a spolehlivou. Pro zobrazení a aplikaci aktualizací můžete použít GUI správce softwaru typu GNOME Software, nástroj pro příkazovou řádku nebo přímo D-Bus." +msgstr "Cílem tohoto projektu je, aby aktualizace firmwaru na Linuxu probíhala automaticky, bezpečně a spolehlivě. Pro zobrazení a nasazení aktualizací můžete použít správce softwaru s grafickým rozhraním, jako je třeba Software GNOME, nebo nástroj pro příkazovou řádku či přímo rozhraní D-Bus." + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Tento zdroj obsahuje firmware, který není zakázaný, ale zatím je u výrobce stále ve stádiu testování. Měli byste se ujistit, že znáte způsob, jak se vrátit k předchozí verzi firmwaru, kdyby došlo k selhání." #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" @@ -547,6 +831,10 @@ msgstr "Přenášená velikost" msgid "Type" msgstr "Typ" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Nástroj pro práci s firmwarem UEFI" + #. TRANSLATORS: section header for firmware URI msgid "URI" msgstr "URI" @@ -562,6 +850,10 @@ msgstr "Odemknutí zařízení pro umožnění přístupu" msgid "Unlocks the device for firmware access" msgstr "Odemknout zařízení pro přístup k firmwaru" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Během aktualizace zrušit příznak ladění" + #. TRANSLATORS: section header for firmware checksum msgid "Update Checksum" msgstr "Kontrolní součet aktualizace" @@ -574,9 +866,17 @@ msgstr "Popis aktualizace" msgid "Update Location" msgstr "Umístění aktualizace" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Název aktualizace" + #. TRANSLATORS: section header for remote ID, e.g. lvfs-testing msgid "Update Remote ID" -msgstr "Vzdálené ID aktualizace" +msgstr "ID vzdáleného zdroje aktualizace" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Souhrn aktualizace" #. TRANSLATORS: section header for firmware version msgid "Update Version" @@ -585,6 +885,14 @@ msgstr "Verze aktualizace" msgid "Update device firmware on Linux" msgstr "Aktualizace firmwaru zařízení na Linuxu" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "O selhání aktualizace se ví, více informací najdete na této adrese:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Aktualizovat nyní?" + msgid "Update the stored device verification information" msgstr "Aktualizace uložené informace o ověření zařízení" @@ -603,6 +911,18 @@ msgstr "Aktualizovat všechen firmware na nejnovější dostupné verze" msgid "Updating %s from %s to %s... " msgstr "Aktualizuje se %s z verze %s na %s…" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Nahraná zpráva:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Nahrát hlášení nyní?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Když nahrajete hlášení o firmwaru, pomůžete tím výrobcům hardwaru rychle rozpoznat nezdařené a úspěšné aktualizace na reálných zařízeních." + #. TRANSLATORS: remote filename base msgid "Username" msgstr "Uživatelské jméno" @@ -615,10 +935,18 @@ msgstr "Ověřuje se…" msgid "Version" msgstr "Verze" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Čeká se…" + #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Sledovat připojení zařízení podporujících DFU" +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Sledovat změny hardwaru" + #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Zapsat firmware ze souboru do zařízení" @@ -631,5 +959,9 @@ msgstr "Zapsat firmware ze souboru do jednoho oddílu" msgid "Writing…" msgstr "Zapisuje se…" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Váš distributor nemusí schválit některé aktualizace firmwaru kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními." + msgid "fwupd" msgstr "fwupd" diff --git a/po/de.po b/po/de.po index f5cb5eaaf..72e8cfdad 100644 --- a/po/de.po +++ b/po/de.po @@ -3,15 +3,16 @@ # This file is distributed under the same license as the fwupd package. # # Translators: +# Ettore Atalan , 2018 # Marco Tedaldi , 2015 # Wolfgang Stöggl , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" -"Last-Translator: Richard Hughes \n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-27 22:37+0000\n" +"Last-Translator: Ettore Atalan \n" "Language-Team: German (http://www.transifex.com/freedesktop/fwupd/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,15 +20,26 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f Minute verbleibt" +msgstr[1] "%.0f Minuten verbleiben" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" -msgstr "Firmwareaktualisierungen für %s verfügbar:" +msgstr "Firmware-Aktualisierungen für %s verfügbar:" #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Hinzugefügt" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Alter" + #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" @@ -35,23 +47,48 @@ msgstr "Verweis auf %s" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" -msgstr "Einspielen niedrigerer Firmwareversionen zulassen (Downgrade)" +msgstr "Herabstufung von Firmware-Versionen zulassen" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" msgstr "Erneute Installation vorhandener Firmware-Versionen erlauben" +#. TRANSLATORS: explain why we want to upload +msgid "An update requires a reboot to complete." +msgstr "Ein Neustart ist erforderlich, um eine Aktualisierung abzuschließen." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Alle Fragen mit Ja beantworten" + +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Binären Patch anwenden" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Firmware-Aktualisierungen anwenden" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "DFU-fähiges Gerät wieder zurück in Laufzeit einhängen" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribute" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Authentifizierung …" + #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "Legitimierung ist erforderlich, um das Firmware-Downgrade auf einem entfernbaren Gerät durchzuführen" +msgstr "Für eine Herabstufung der Firmware auf einem entfernbaren Gerät ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Auf diesem System ist eine Legitimierung erforderlich, um das Firmware-Downgrade durchzuführen" +msgstr "Für eine Herabstufung der Firmware auf diesem System ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" @@ -59,11 +96,23 @@ msgstr "Legitimation ist zum Entsperren eines Geräts erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on a removable device" -msgstr "Legitimierung ist notwendig, um die Firmware auf einem entfernbaren Gerät zu aktualisieren" +msgstr "Für die Aktualisierung der Firmware auf einem entfernbaren Gerät ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to update the firmware on this machine" -msgstr "Auf diesem System ist eine Authentifizierung notwendig, um das Firmware Update durch zu führen" +msgstr "Für die Aktualisierung der Firmware auf diesem System ist eine Authentifizierung erforderlich" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Eine Authentifizierung ist erforderlich, um die gespeicherten Prüfsummen für das Gerät zu aktualisieren" + +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Firmware mit Hilfe einer Sandbox erstellen" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Abbrechen" #. TRANSLATORS: this is when a device ctrl+c's a watch msgid "Cancelled" @@ -79,6 +128,18 @@ msgstr "Geändert" msgid "Checksum" msgstr "Prüfsumme" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chip-Kennung" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Wählen Sie ein Gerät aus:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Wählen Sie eine Version aus:" + #. TRANSLATORS: this is the encryption method used when writing msgid "Cipher" msgstr "Verschlüsselungsverfahren" @@ -95,9 +156,16 @@ msgstr "Befehl nicht gefunden" msgid "Convert firmware to DFU format" msgstr "Firmware in das DFU-Format konvertieren" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Binären Patch aus zwei Dateien erstellen" + +msgid "DFU" +msgstr "DFU" + #. TRANSLATORS: DFU stands for device firmware update msgid "DFU Utility" -msgstr "DFU-Werkzeug" +msgstr "DFU-Dienstprogramm" #. TRANSLATORS: for the --verbose arg msgid "Debugging Options" @@ -109,7 +177,7 @@ msgstr "Entpacken …" #. TRANSLATORS: command description msgid "Decrypt firmware data" -msgstr "Firmwaredaten entschlüsseln" +msgstr "Firmware-Daten entschlüsseln" #. TRANSLATORS: section header for firmware description msgid "Description" @@ -131,23 +199,101 @@ msgstr "Gerät geändert:" msgid "Device removed:" msgstr "Gerät entfernt:" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Erfolgreich aktualisierte Geräte:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Nicht korrekt aktualisierte Geräte:" + +msgid "Disabled fwupdate debugging" +msgstr "fwupdate-Defektlokalisierung deaktivieren" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Version anzeigen" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Nicht auf alte Metadaten prüfen" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Nach der Aktualisierung nicht auf einen Neustart prüfen" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Nicht auf nicht erfassten Verlauf prüfen" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Nicht in die Verlaufsdatenbank schreiben" + msgid "Done!" msgstr "Fertig." +#. TRANSLATORS: command description +msgid "Downgrades the firmware on a device" +msgstr "Stuft die Firmware auf einem Gerät herab" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" #, c-format msgid "Downgrading %s from %s to %s... " -msgstr "Downgrade für %s von %s auf %s wird eingespielt …" +msgstr "Herabstufung für %s von %s auf %s wird eingespielt…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "%s wird herabgestuft …" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Herunterladen …" + +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "SMBIOS-Daten aus einer Datei ausgeben" #. TRANSLATORS: command description msgid "Dump details about a firmware file" msgstr "Details zu einer Firmware-Datei ausgeben" +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Informationen über einen binären Patch auf dem Bildschirm ausgeben" + +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Das angegebene ESP war nicht gültig" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Firmware-Aktualisierungsunterstützung auf unterstützten Systemen aktivieren" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Aktiviert" + +msgid "Enabled fwupdate debugging" +msgstr "fwupdate-Defektlokalisierung aktivieren" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Die Aktivierung dieser Funktionalität erfolgt auf eigene Gefahr, d.h. Sie müssen sich bei Problemen, die durch diese Aktualisierungen verursacht werden, an Ihren Erstausrüster wenden. Nur Probleme mit dem Aktualisierungsprozess selbst sollten unter $OS_RELEASE:BUG_REPORT_URL$ eingereicht werden." + #. TRANSLATORS: command description msgid "Encrypt firmware data" -msgstr "Firmwaredaten verschlüsseln" +msgstr "Firmware-Daten verschlüsseln" + +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Gesamten Firmware-Aktualisierungsverlauf löschen" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Löschen …" #. TRANSLATORS: exit after we've started up, used for user profiling msgid "Exit after a small delay" @@ -161,17 +307,61 @@ msgstr "Nach dem Laden der Engine beenden" msgid "Failed to parse arguments" msgstr "Verarbeitung der Argumente schlug fehl" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Datei wird abgerufen" + +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Firmware wird abgerufen" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Metadaten werden abgerufen" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Signatur wird abgerufen" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Dateiname" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Signatur des Dateinamens" + +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Firmware Basis-URI" + #. TRANSLATORS: program summary msgid "Firmware Update D-Bus Service" msgstr "D-Bus-Dienst für Firmware-Aktualisierung" #. TRANSLATORS: program name msgid "Firmware Update Daemon" -msgstr "Dienst für Firmware-Aktualisierung" +msgstr "Hintergrundprogramm für Firmware-Aktualisierung" #. TRANSLATORS: program name msgid "Firmware Utility" -msgstr "Firmware-Werkzeug" +msgstr "Firmware-Dienstprogramm" + +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Firmware-Metadaten wurden seit %u Tag nicht aktualisiert und sind möglicherweise nicht auf dem neuesten Stand." +msgstr[1] "Firmware-Metadaten wurden seit %u Tagen nicht aktualisiert und sind möglicherweise nicht auf dem neuesten Stand." + +msgid "Firmware updates are not supported on this machine." +msgstr "Firmware-Aktualisierungen werden auf diesem System nicht unterstützt." + +msgid "Firmware updates are supported on this machine." +msgstr "Firmware-Aktualisierungen werden auf diesem System unterstützt." + +msgid "Force the action ignoring all warnings" +msgstr "Aktion erzwingen, bei der alle Warnungen ignoriert werden" #. TRANSLATORS: detected a DFU device msgid "Found" @@ -180,10 +370,18 @@ msgstr "Gefunden" msgid "GUID" msgstr "GUID" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Ermittelt alle Geräte gemäß der Systemtopologie" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Alle Geräte ermitteln, die Firmware-Aktualisierungen unterstützen" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Alle aktivierten und im System registrierten Plugins ermitteln" + #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Ermittelt Details über eine Firmware-Datei" @@ -196,6 +394,10 @@ msgstr "Ermittelt den kryptographischen Hash-Wert der abgelegten Firmware" msgid "Gets the list of updates for connected hardware" msgstr "Ermittelt die Liste der Aktualisierungen für angeschlossene Hardware" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Ermittelt die Versionen für ein Gerät" + #. TRANSLATORS: command description msgid "Gets the results from the last update" msgstr "Ermittelt die Ergebnisse der letzten Aktualisierung" @@ -208,6 +410,10 @@ msgstr "Kennung" msgid "Idle…" msgstr "Bereit …" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Firmware-Blob auf einem Gerät installieren" + #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Eine Firmware-Datei auf dieser Hardware installieren" @@ -231,10 +437,42 @@ msgstr "Nicht-signierte Geräte-Firmware installieren" msgid "Install unsigned system firmware" msgstr "Nicht-signierte System-Firmware installieren" +#. show message in progressbar +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing %s" +msgstr "%s wird installiert" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Firmware-Aktualisierung wird installiert …" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Wird auf %s installiert …" + +msgid "Keyring" +msgstr "Schlüsselbund" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Weniger als eine Minute verbleiben" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabile Firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (Test-Firmware)" + #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Derzeit angeschlossene DFU-fähige Geräte auflisten" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Unterstützte Firmware-Aktualisierungen auflisten" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Laden …" @@ -243,12 +481,24 @@ msgstr "Laden …" msgid "Merge multiple firmware files into one" msgstr "Mehrere Firmware-Dateien in eine zusammenführen" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadaten-URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadaten URI-Signatur" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadaten können über den Linux Vendor Firmware Service bezogen werden." + msgid "Mode" msgstr "Modus" #. TRANSLATORS: command description msgid "Monitor the daemon for events" -msgstr "Den Daemon auf Ereignisse überwachen" +msgstr "Hintergrundprogramm auf Ereignisse überwachen" #. TRANSLATORS: interface name, e.g. "Flash" #. TRANSLATORS: device name, e.g. 'ColorHug2' @@ -256,18 +506,65 @@ msgstr "Den Daemon auf Ereignisse überwachen" msgid "Name" msgstr "Name" +msgid "No action specified!" +msgstr "Keine Aktion angegeben!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Es wurde keine Hardware erkannt, deren Firmware aktualisiert werden kann" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Keine Plugins gefunden" + msgid "OK" msgstr "Ok" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Plugin-Warnung überschreiben" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Standard-ESP-Pfad überschreiben" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Passwort" + +msgid "Payload" +msgstr "Nutzdaten" + +msgid "Permission denied" +msgstr "Berechtigung verweigert" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Bitte geben Sie eine Zahl von 0 bis %u ein: " + +msgid "Print the version number" +msgstr "Versionsnummer ausgeben" + +msgid "Print verbose debug statements" +msgstr "Ausführliche Debug-Anweisungen ausgeben" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorität" + +msgid "Proceed with upload?" +msgstr "Mit dem Hochladen fortfahren?" + #. TRANSLATORS: DFU protocol version, e.g. 1.1 msgid "Protocol" msgstr "Protokoll" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Abfrage der Unterstützung für Firmware-Aktualisierungen" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -281,6 +578,10 @@ msgstr "Firmware von Gerät in Datei schreiben" msgid "Read firmware from one partition into a file" msgstr "Firmware von einzelner Partition in Datei lesen" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lesen …" + #. TRANSLATORS: command description msgid "Refresh metadata from remote server" msgstr "Metadaten von entferntem Server aktualisieren" @@ -300,10 +601,41 @@ msgstr "Erneute Installation von %s mit %s …" msgid "Removed" msgstr "Entfernt" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Daten in einer bestehenden Firmware-Datei ersetzen" + +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Bericht-URI" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Erfordert Internetverbindung" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "DFU-Gerät zurücksetzen" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Jetzt neu starten?" + #. TRANSLATORS: restarting the device to pick up new F/W msgid "Restarting device…" msgstr "Gerät wird neu gestartet …" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Alle Hardware-Kennungen für das System zurückgeben" + +msgid "Runtime" +msgstr "Laufzeit" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Installation für den nächsten Neustart planen, falls möglich" + #. TRANSLATORS: scheduing an update to be done on the next boot msgid "Scheduling…" msgstr "Einplanen …" @@ -334,7 +666,7 @@ msgstr "Veröffentlichungsversion einer Firmware-Datei festlegen" #. TRANSLATORS: command description msgid "Set the firmware size for the target" -msgstr "Die Firmware-Größe für das Ziel festlegen" +msgstr "Firmware-Größe für das Ziel festlegen" #. TRANSLATORS: command description msgid "Set vendor ID on firmware file" @@ -344,6 +676,18 @@ msgstr "Hersteller-Kennung einer Firmware-Datei festlegen" msgid "Sets metadata on a firmware file" msgstr "Metadaten einer Firmware-Datei festlegen" +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Firmware-Verlauf mit den Entwicklern teilen" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Client- und Hintergrundprogramm-Versionen anzeigen" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Ausführliche Informationen zum Dienstprogramm anzeigen" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Debuginformationen für alle Dateien anzeigen" @@ -352,10 +696,33 @@ msgstr "Debuginformationen für alle Dateien anzeigen" msgid "Show debugging options" msgstr "Debug Optionen anzeigen" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Nicht aktualisierbare Geräte anzeigen" + #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Zusätzliche Informationen zur Fehlerdiagnose anzeigen" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Verlauf von Firmware-Aktualisierungen anzeigen" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Ausführliche Informationen zum Plugin anzeigen" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Fehlerprotokoll der letzten versuchten Aktualisierung anzeigen" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Informationen über den Firmware-Aktualisierungsstatus anzeigen" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Geben Sie die Anzahl der Bytes pro USB-Übertragung an" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Zustand" @@ -366,6 +733,51 @@ msgstr "Zustand" msgid "Status" msgstr "Status" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Zusammenfassung" + +msgid "Target" +msgstr "Ziel" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "Der LVFS ist ein kostenloser Dienst, der als unabhängige juristische Person arbeitet und keine Verbindung zu $OS_RELEASE:NAME$ hat. Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft. Die gesamte Firmware wird nur vom Originalhersteller zur Verfügung gestellt." + +msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." +msgstr "Der fwupd-Prozess ist ein einfaches Hintergrundprogramm, der es der Sitzungssoftware ermöglicht, die Geräte-Firmware auf Ihrem lokalen System zu aktualisieren. Es ist für Desktops konzipiert, aber dieses Projekt ist auch auf Telefonen, Tablets und Headless-Servern einsetzbar." + +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "Ein Neustart ist erforderlich, um die Aktualisierung abzuschließen." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Dieses Programm funktioniert möglicherweise nur als root korrekt" + +msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." +msgstr "Ziel dieses Projekts ist es, die Aktualisierung der Firmware unter Linux automatisch, sicher und zuverlässig zu machen. Zum Anzeigen und Anwenden von Aktualisierungen können Sie entweder eine GUI-Softwareverwaltung wie GNOME Software, das Befehlszeilenwerkzeug oder die D-Bus-Schnittstelle direkt verwenden." + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Übertragungsgröße" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Typ" + +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI-Firmware-Dienstprogramm" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + #. TRANSLATORS: currect daemon status is unknown msgid "Unknown" msgstr "Unbekannt" @@ -389,10 +801,32 @@ msgstr "Beschreibung aktualisieren" msgid "Update Location" msgstr "Ort aktualisieren" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Aktualisierungsname" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Aktualisierungszusammenfassung" + #. TRANSLATORS: section header for firmware version msgid "Update Version" msgstr "Version aktualisieren" +msgid "Update device firmware on Linux" +msgstr "Geräte-Firmware unter Linux aktualisieren" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Der Aktualisierungsfehler ist ein bekanntes Problem, besuchen Sie diese URL für weitere Informationen:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Jetzt aktualisieren?" + +msgid "Update the stored device verification information" +msgstr "Gespeicherte Geräteverifizierungsinformationen aktualisieren" + #. TRANSLATORS: command description msgid "Update the stored metadata with current ROM contents" msgstr "Gespeicherte Metadaten mit dem aktuellen ROM-Inhalt aktualisieren" @@ -408,18 +842,47 @@ msgstr "Alle Firmware auf die neueste verfügbare Version aktualisieren" msgid "Updating %s from %s to %s... " msgstr "Aktualisieren von %s von %s nach %s …" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "%s wird aktualisiert …" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Nachricht beim Hochladen:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Bericht jetzt hochladen?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Das Hochladen von Firmware-Berichten hilft Hardwareherstellern, fehlerhafte und erfolgreiche Aktualisierungen auf realen Geräten schnell zu erkennen." + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Benutzername" + #. TRANSLATORS: verifying we wrote the firmware correctly msgid "Verifying…" -msgstr "Überprüfung läuft …" +msgstr "Überprüfung …" #. TRANSLATORS: section header for release version number msgid "Version" msgstr "Version" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Warten …" + #. TRANSLATORS: command description msgid "Watch DFU devices being hotplugged" msgstr "Geräteanschluss von DFU-Geräten überwachen" +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Auf Hardware-Änderungen achten" + #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Firmware von Datei auf Gerät schreiben" @@ -431,3 +894,10 @@ msgstr "Firmware aus Datei in einzelne Partition schreiben" #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Schreiben …" + +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft." + +msgid "fwupd" +msgstr "fwupd" diff --git a/po/en_GB.po b/po/en_GB.po index 5a93e1c58..d6b2a2c5c 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/freedesktop/fwupd/language/en_GB/)\n" "MIME-Version: 1.0\n" diff --git a/po/fi.po b/po/fi.po index cc6427acc..0e501ab0d 100644 --- a/po/fi.po +++ b/po/fi.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Finnish (http://www.transifex.com/freedesktop/fwupd/language/fi/)\n" "MIME-Version: 1.0\n" diff --git a/po/fr.po b/po/fr.po index 5c58272ad..2da1ac94a 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: French (http://www.transifex.com/freedesktop/fwupd/language/fr/)\n" "MIME-Version: 1.0\n" diff --git a/po/fur.po b/po/fur.po index 19f1e453a..d18122f44 100644 --- a/po/fur.po +++ b/po/fur.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Friulian (http://www.transifex.com/freedesktop/fwupd/language/fur/)\n" "MIME-Version: 1.0\n" diff --git a/po/he.po b/po/he.po index 875678cd6..58ed9a36a 100644 --- a/po/he.po +++ b/po/he.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hebrew (http://www.transifex.com/freedesktop/fwupd/language/he/)\n" "MIME-Version: 1.0\n" diff --git a/po/hi.po b/po/hi.po index 1ebeb988c..4a990c8e1 100644 --- a/po/hi.po +++ b/po/hi.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hindi (http://www.transifex.com/freedesktop/fwupd/language/hi/)\n" "MIME-Version: 1.0\n" diff --git a/po/hr.po b/po/hr.po index 5e99d562b..7784f6240 100644 --- a/po/hr.po +++ b/po/hr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Croatian (http://www.transifex.com/freedesktop/fwupd/language/hr/)\n" "MIME-Version: 1.0\n" diff --git a/po/hu.po b/po/hu.po index 03a3f53e6..0acb31339 100644 --- a/po/hu.po +++ b/po/hu.po @@ -4,15 +4,15 @@ # # Translators: # Balázs Meskó , 2017-2018 -# Balázs Úr , 2015-2018 +# Balázs Úr , 2015-2018 # Gabor Kelemen , 2016 # kelemeng , 2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hungarian (http://www.transifex.com/freedesktop/fwupd/language/hu/)\n" "MIME-Version: 1.0\n" diff --git a/po/id.po b/po/id.po index ff1fc8aae..3dc783e54 100644 --- a/po/id.po +++ b/po/id.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Indonesian (http://www.transifex.com/freedesktop/fwupd/language/id/)\n" "MIME-Version: 1.0\n" diff --git a/po/it.po b/po/it.po index ab60e5676..944c46288 100644 --- a/po/it.po +++ b/po/it.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-10 16:44+0100\n" -"PO-Revision-Date: 2018-09-10 15:45+0000\n" -"Last-Translator: Richard Hughes \n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 13:29+0000\n" +"Last-Translator: Milo Casagrande \n" "Language-Team: Italian (http://www.transifex.com/freedesktop/fwupd/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +19,13 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Manca %.0f minuto" +msgstr[1] "Mancano %.0f minuti" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" @@ -260,10 +267,10 @@ msgstr "Ripristina una vecchia versione del firmare su un dispositivo" msgid "Downgrading %s from %s to %s... " msgstr "Arretramento di %s da %s a %s..." -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s…" -msgstr "Arretramento di %s da %s a %s…" +msgid "Downgrading %s…" +msgstr "Arretramento di %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -396,6 +403,9 @@ msgstr "Gli aggiornamenti firmware non sono supportati su questo dispositivo." msgid "Firmware updates are supported on this machine." msgstr "Gli aggiornamenti firmware sono supportati su questo dispositivo." +msgid "Force the action ignoring all warnings" +msgstr "Forza l'azione ignorando gli avvisi" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Trovato" @@ -484,9 +494,18 @@ msgstr "Installazione di %s" msgid "Installing firmware update…" msgstr "Installazione aggiornamento firmware…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installazione su %s…" + msgid "Keyring" msgstr "Portachiavi" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Manca meno di un minuto" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux Vendor Firmware Service (firmware stabile)" @@ -587,6 +606,12 @@ msgstr "Permesso negato" msgid "Please enter a number from 0 to %u: " msgstr "Inserire un numero tra 0 e %u:" +msgid "Print the version number" +msgstr "Stampa il numero di versione" + +msgid "Print verbose debug statements" +msgstr "Stampa messaggi di debug prolissi" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Priorità" @@ -733,6 +758,10 @@ msgstr "Condivide la cronologia del firmware con gli sviluppatori" msgid "Show client and daemon versions" msgstr "Mostra la versione del client e del demone" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Mostra informazioni prolisse del demone" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostra le informazioni di debug per tutti i file" @@ -765,6 +794,12 @@ msgstr "Mostra debug dell'ultimo tentativo di aggiornamento" msgid "Show the information of firmware update status" msgstr "Mostra informazioni sullo stato degli aggiornamenti firmware" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Specifica vendor/ID prodotto di un dispositivo DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Specifica il numero di byte per trasferimento USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stato" @@ -789,6 +824,10 @@ msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." msgstr "Il processo fwupd è un demone che consente di aggiornare il firmware di un dispositivo sul proprio computer. È progettato per un ambiente desktop, ma è possibile utilizzarlo anche su telefonini, tablet e server." +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "Per essere completato, l'aggiornamento richiede un riavvio." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Questo programma può funzionare correttamente solo come utente root" @@ -891,10 +930,10 @@ msgstr "Aggiorna tutti i firmware all'ultima versione disponibile" msgid "Updating %s from %s to %s... " msgstr "Aggiornamento di %s da %s a %s..." -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s…" -msgstr "Aggiornamento di %s da %s a %s…" +msgid "Updating %s…" +msgstr "Aggiornamento di %s…" #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" diff --git a/po/ko.po b/po/ko.po index 34d166a95..62cf045d2 100644 --- a/po/ko.po +++ b/po/ko.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-08-13 12:41+0100\n" -"PO-Revision-Date: 2018-08-13 11:42+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Korean (http://www.transifex.com/freedesktop/fwupd/language/ko/)\n" "MIME-Version: 1.0\n" diff --git a/po/ky.po b/po/ky.po new file mode 100644 index 000000000..742e6ae91 --- /dev/null +++ b/po/ky.po @@ -0,0 +1,73 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# Ilyas Bakirov , 2018 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"Last-Translator: Richard Hughes \n" +"Language-Team: Kyrgyz (http://www.transifex.com/freedesktop/fwupd/language/ky/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ky\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Кошулду" + +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Чиптин ID'си" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Табылды" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. show message in progressbar +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing %s" +msgstr "Орнотулууда: %s" + +msgid "Mode" +msgstr "Режими" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Протокол" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Окуулууда..." + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Абалы" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Статус" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Белгисиз" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Жазылууда..." + +msgid "fwupd" +msgstr "fwupd" diff --git a/po/nl.po b/po/nl.po index a5e6dcd4a..6644a59ad 100644 --- a/po/nl.po +++ b/po/nl.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Dutch (http://www.transifex.com/freedesktop/fwupd/language/nl/)\n" "MIME-Version: 1.0\n" diff --git a/po/oc.po b/po/oc.po index 050f8c4cb..eb3b1a9b0 100644 --- a/po/oc.po +++ b/po/oc.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Occitan (post 1500) (http://www.transifex.com/freedesktop/fwupd/language/oc/)\n" "MIME-Version: 1.0\n" diff --git a/po/pl.po b/po/pl.po index 3dd1f3fa1..4686792b4 100644 --- a/po/pl.po +++ b/po/pl.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-10 16:44+0100\n" -"PO-Revision-Date: 2018-09-10 15:45+0000\n" -"Last-Translator: Richard Hughes \n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 15:22+0000\n" +"Last-Translator: Piotr Drąg \n" "Language-Team: Polish (http://www.transifex.com/freedesktop/fwupd/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,6 +18,15 @@ msgstr "" "Language: pl\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Pozostała %.0f minuta" +msgstr[1] "Pozostały %.0f minuty" +msgstr[2] "Pozostało %.0f minut" +msgstr[3] "Pozostało %.0f minut" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" @@ -259,10 +268,10 @@ msgstr "Instaluje poprzednią wersję oprogramowania sprzętowego urządzenia" msgid "Downgrading %s from %s to %s... " msgstr "Instalowanie poprzedniej wersji %s z %s do %s… " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s…" -msgstr "Instalowanie poprzedniej wersji urządzenia %s z %s na %s…" +msgid "Downgrading %s…" +msgstr "Instalowanie poprzedniej wersji urządzenia %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -397,6 +406,9 @@ msgstr "Aktualizacje oprogramowania sprzętowego nie są obsługiwane na tym kom msgid "Firmware updates are supported on this machine." msgstr "Aktualizacje oprogramowania sprzętowego są obsługiwane na tym komputerze." +msgid "Force the action ignoring all warnings" +msgstr "Wymusza działanie ignorując wszystkie ostrzeżenia" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Odnaleziono" @@ -485,9 +497,18 @@ msgstr "Instalowanie urządzenia %s" msgid "Installing firmware update…" msgstr "Instalowanie aktualizacji oprogramowania sprzętowego…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Instalowanie na urządzeniu %s…" + msgid "Keyring" msgstr "Baza kluczy" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Pozostała mniej niż jedna minuta" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux Vendor Firmware Service (stabilne oprogramowanie sprzętowe)" @@ -588,6 +609,12 @@ msgstr "Brak uprawnień" msgid "Please enter a number from 0 to %u: " msgstr "Proszę podać liczbę od 0 do %u:" +msgid "Print the version number" +msgstr "Wyświetla numer wersji" + +msgid "Print verbose debug statements" +msgstr "Wyświetla więcej komunikatów debugowania" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Priorytet" @@ -734,6 +761,10 @@ msgstr "Udostępnia historię oprogramowania sprzętowego programistom" msgid "Show client and daemon versions" msgstr "Wyświetla wersje klienta i usługi" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Wyświetla więcej informacji o usłudze" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Wyświetla informacje o debugowaniu dla wszystkich plików" @@ -766,6 +797,12 @@ msgstr "Wyświetla dziennik debugowania z ostatniej aktualizacji" msgid "Show the information of firmware update status" msgstr "Wyświetla informacje o stanie aktualizacji oprogramowania sprzętowego" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Podaje identyfikatory dostawcy/produktu urządzenia DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Podaje liczbę bajtów na przesyłanie USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Stan" @@ -790,6 +827,10 @@ msgstr "LVFS to wolny serwis działający jako niezależny podmiot prawny niemaj msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." msgstr "Proces fwupd to prosta usługa umożliwiająca aktualizowanie oprogramowania sprzętowego komputera w sesji użytkownika. Jest zaprojektowana dla komputerów osobistych, ale można jej używać także na telefonach, tabletach i serwerach bez monitorów." +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Ten program może działać poprawnie tylko jako root" @@ -892,10 +933,10 @@ msgstr "Aktualizuje całe oprogramowanie sprzętowe do najnowszych dostępnych w msgid "Updating %s from %s to %s... " msgstr "Aktualizowanie %s z wersji %s do %s… " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s…" -msgstr "Aktualizowanie urządzenia %s z wersji %s do %s…" +msgid "Updating %s…" +msgstr "Aktualizowanie urządzenia %s…" #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" diff --git a/po/pt_BR.po b/po/pt_BR.po index cddc39694..78c804b1e 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-10 16:44+0100\n" -"PO-Revision-Date: 2018-09-10 15:45+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/freedesktop/fwupd/language/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -263,11 +263,6 @@ msgstr "Retrocede a versão do firmware em um dispositivo" msgid "Downgrading %s from %s to %s... " msgstr "Revertendo %s de %s para %s… " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers -#, c-format -msgid "Downgrading %s from %s to %s…" -msgstr "Revertendo %s de %s para %s…" - #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Baixando…" @@ -894,11 +889,6 @@ msgstr "Atualiza todos os firmwares para a última versão disponível" msgid "Updating %s from %s to %s... " msgstr "Atualizando %s de %s para %s… " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers -#, c-format -msgid "Updating %s from %s to %s…" -msgstr "Atualizando %s de %s para %s…" - #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Mensagem enviada:" diff --git a/po/ru.po b/po/ru.po index 88d4831b7..be5d8dcad 100644 --- a/po/ru.po +++ b/po/ru.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Russian (http://www.transifex.com/freedesktop/fwupd/language/ru/)\n" "MIME-Version: 1.0\n" diff --git a/po/sk.po b/po/sk.po index 375891401..257221444 100644 --- a/po/sk.po +++ b/po/sk.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Slovak (http://www.transifex.com/freedesktop/fwupd/language/sk/)\n" "MIME-Version: 1.0\n" diff --git a/po/sr.po b/po/sr.po index e75bb0f3f..a62d7be28 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Serbian (http://www.transifex.com/freedesktop/fwupd/language/sr/)\n" "MIME-Version: 1.0\n" diff --git a/po/sv.po b/po/sv.po index 5dbe6f9ed..8d9f4287a 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,13 +7,13 @@ # Andreas Henriksson , 2017 # Josef Andersson , 2015,2017-2018 # Josef Andersson , 2015,2017 -# sebras , 2018 +# Sebastian Rasmussen , 2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Swedish (http://www.transifex.com/freedesktop/fwupd/language/sv/)\n" "MIME-Version: 1.0\n" diff --git a/po/tr.po b/po/tr.po index 979dacebd..1377a3a9e 100644 --- a/po/tr.po +++ b/po/tr.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Turkish (http://www.transifex.com/freedesktop/fwupd/language/tr/)\n" "MIME-Version: 1.0\n" diff --git a/po/uk.po b/po/uk.po index 7d19b7314..dd01c2add 100644 --- a/po/uk.po +++ b/po/uk.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-10 16:44+0100\n" -"PO-Revision-Date: 2018-09-10 15:45+0000\n" -"Last-Translator: Richard Hughes \n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 12:46+0000\n" +"Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian (http://www.transifex.com/freedesktop/fwupd/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,6 +18,15 @@ msgstr "" "Language: uk\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Лишилася %.0f хвилина" +msgstr[1] "Лишилося %.0f хвилини" +msgstr[2] "Лишилося %.0f хвилин" +msgstr[3] "Лишилася %.0f хвилина" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" @@ -259,10 +268,10 @@ msgstr "Знижує версію мікропрограми на пристро msgid "Downgrading %s from %s to %s... " msgstr "Знижуємо версію %s з %s до %s... " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s…" -msgstr "Знижуємо версію для %s з %s до %s…" +msgid "Downgrading %s…" +msgstr "Знижуємо версію %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -397,6 +406,9 @@ msgstr "На цьому комп'ютері не передбачено підт msgid "Firmware updates are supported on this machine." msgstr "На цьому комп'ютері передбачено підтримку оновлень мікропрограми." +msgid "Force the action ignoring all warnings" +msgstr "Виконати дію примусово, ігноруючи усі попередження" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Знайдено" @@ -485,9 +497,18 @@ msgstr "Встановлюємо %s" msgid "Installing firmware update…" msgstr "Встановлюємо оновлення мікропрограми…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Встановлюємо на %s…" + msgid "Keyring" msgstr "Сховище ключів" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Лишилося менше за хвилину" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Служба надання мікропрограм для Linux від виробника (стабільна мікропрограма)" @@ -588,6 +609,12 @@ msgstr "Доступ заборонено" msgid "Please enter a number from 0 to %u: " msgstr "Будь ласка, введіть число від 0 до %u: " +msgid "Print the version number" +msgstr "Вивести номер версії" + +msgid "Print verbose debug statements" +msgstr "Вивести докладні діагностичні повідомлення" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Пріоритетність" @@ -734,6 +761,10 @@ msgstr "Поділитися журналом оновлень із розроб msgid "Show client and daemon versions" msgstr "Вивести дані щодо версій клієнат і фонової служби" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Показати докладні відомості щодо фонової служби" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Показувати діагностичні дані для всіх файлів" @@ -766,6 +797,12 @@ msgstr "Показати діагностичний журнал щодо ост msgid "Show the information of firmware update status" msgstr "Показати дані щодо стану оновлення мікропрограми" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Вказати ідентифікатори виробника/продукту пристрою DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Вказати кількість байтів на один пакет передавання даних USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Стан" @@ -790,6 +827,10 @@ msgstr "LVFS є безкоштовною службою, яка працює я msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." msgstr "Процес fwupd є простою фоновою службою, яка надає змогу оновлювати мікропрограми пристроїв на вашому локальному комп’ютері у межах сеансу користування. Програму розроблено для робочих станцій, але нею можна скористатися на телефонах, планшетах та серверах без дисплеїв." +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "Для завершення оновлення потрібне перезавантаження." + #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Програма зможе працювати належними чином лише від імені користувача root" @@ -892,10 +933,10 @@ msgstr "Оновлює усі мікропрограми до найновіши msgid "Updating %s from %s to %s... " msgstr "Оновлюємо %s з %s до %s... " -#. TRANSLATORS: %1 is a device name, and %2 and %3 are version numbers +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s…" -msgstr "Оновлюємо %s з %s до %s…" +msgid "Updating %s…" +msgstr "Оновлюємо %s…" #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" diff --git a/po/zh_CN.po b/po/zh_CN.po index 8b016dde9..65281a06b 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-10 16:44+0100\n" -"PO-Revision-Date: 2018-09-10 15:45+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Chinese (China) (http://www.transifex.com/freedesktop/fwupd/language/zh_CN/)\n" "MIME-Version: 1.0\n" diff --git a/po/zh_TW.po b/po/zh_TW.po index bcaf1b0d9..4b2976a20 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" +"POT-Creation-Date: 2018-11-07 11:16+0000\n" +"PO-Revision-Date: 2018-10-12 11:10+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/freedesktop/fwupd/language/zh_TW/)\n" "MIME-Version: 1.0\n" @@ -18,6 +18,12 @@ msgstr "" "Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0;\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "剩下 %.0f 分鐘" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" @@ -31,6 +37,10 @@ msgstr "已加入" msgid "Age" msgstr "年紀" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "同意並且啟用遠端站點?" + #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" @@ -56,10 +66,18 @@ msgstr "全部的問題都回答是" msgid "Apply a binary patch" msgstr "套用二進位補丁" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "套用韌體更新" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "將 DFU 能力裝置接回執行時期" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "連接至韌體模式" + #. TRANSLATORS: device attributes, i.e. things that #. * the device can do msgid "Attributes" @@ -79,7 +97,7 @@ msgstr "必須先通過身份核對才能降級這臺機器上的韌體" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify a configured remote used for firmware updates" -msgstr "必須通過身份核對才能修改設定作韌體更新的遠端" +msgstr "必須通過身份核對才能修改設定作韌體更新的遠端站點" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to unlock a device" @@ -182,6 +200,10 @@ msgstr "描述說明" msgid "Detach currently attached DFU capable device" msgstr "解開目前接上的 DFU 能力裝置" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "斷開至開機載入器模式" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "裝置已加入:" @@ -202,6 +224,17 @@ msgstr "成功更新的裝置:" msgid "Devices that were not updated correctly:" msgstr "無法正確更新的裝置:" +msgid "Disabled fwupdate debugging" +msgstr "已停用 fwupdate 除錯" + +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "停用指定的遠端站點" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "顯示版本" + #. TRANSLATORS: command line option msgid "Do not check for old metadata" msgstr "不要檢查中介資料是否老舊" @@ -214,6 +247,10 @@ msgstr "不要檢查是否更新後要重新開機" msgid "Do not check for unreported history" msgstr "不要檢查是否有尚未報告的歷史" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "不要寫入歷史資料庫中" + msgid "Done!" msgstr "完成!" @@ -226,7 +263,7 @@ msgstr "降級裝置的韌體" #. * version numbers e.g. "1.2.3" #, c-format msgid "Downgrading %s from %s to %s... " -msgstr "正降級 %s 從 %s 版至 %s 版…" +msgstr "正將 %s 從 %s 版降級至 %s 版... " #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -244,10 +281,36 @@ msgstr "傾印韌體檔案的相關細節" msgid "Dump information about a binary patch to the screen" msgstr "傾印二進位補丁相關資訊至螢幕上" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "指定的 ESP 無效" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "對支援的系統啟用韌體更新支援" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "啟用此遠端站點?" + #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "啟用" +msgid "Enabled fwupdate debugging" +msgstr "已啟用 fwupdate 除錯" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "啟用指定的遠端站點" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "啟用此功能必須自負風險。這代表若您遭遇到這些更新導致的任何問題,您必須向原始設備供應商聯絡並反應。只有在您遇到更新過程本身的問題時,才是向 $OS_RELEASE:BUG_REPORT_URL$ 回報。" + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "若要啟用此遠端站點,請自負風險。" + #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "加密韌體資料" @@ -268,6 +331,10 @@ msgstr "經過一段短暫延遲後便離開" msgid "Exit after the engine has loaded" msgstr "引擎載入後離開" +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "因伺服器限制而下載失敗" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "無法載入奇技淫巧" @@ -322,6 +389,12 @@ msgid "Firmware metadata has not been updated for %u day and may not be up to da msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." msgstr[0] "韌體中介資料已有 %u 天未更新,可能不是最新狀態。" +msgid "Firmware updates are not supported on this machine." +msgstr "此機器沒有韌體更新支援。" + +msgid "Firmware updates are supported on this machine." +msgstr "此機器有韌體更新支援。" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "找到" @@ -329,17 +402,25 @@ msgstr "找到" msgid "GUID" msgstr "GUID" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "取得根據系統拓樸而得的所有裝置" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "取得所有支援韌體更新的裝置" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "取得所有系統中註冊的啟用插件" + #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "取得韌體檔案的相關細節" #. TRANSLATORS: command description msgid "Gets the configured remotes" -msgstr "取得設定的遠端" +msgstr "取得設定的遠端站點" #. TRANSLATORS: command description msgid "Gets the cryptographic hash of the dumped firmware" @@ -365,6 +446,10 @@ msgstr "ID" msgid "Idle…" msgstr "閒置…" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "在裝置上安裝韌體 blob" + #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "在此硬體安裝韌體檔案" @@ -388,21 +473,50 @@ msgstr "安裝未簽署的裝置韌體" msgid "Install unsigned system firmware" msgstr "安裝未簽署的系統韌體" +#. show message in progressbar +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing %s" +msgstr "正安裝 %s" + #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "安裝韌體更新中…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "正安裝到 %s…" + msgid "Keyring" msgstr "鑰匙圈" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "剩不到一分鐘" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux 廠商韌體服務(穩定版韌體)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux 廠商韌體服務(測試中韌體)" + #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "列出目前接上的 DFU 能力裝置" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "列出支援的韌體更新" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "載入中…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "手動白名單指定插件" + #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "合併多份韌體檔案為一份" @@ -415,15 +529,19 @@ msgstr "中介資料 URI" msgid "Metadata URI Signature" msgstr "中介資料 URI 簽章" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "中介資料可從 Linux 廠商韌體服務取得。" + msgid "Mode" msgstr "模式" #. TRANSLATORS: command description msgid "Modifies a given remote" -msgstr "修改指定的遠端" +msgstr "修改指定的遠端站點" msgid "Modify a configured remote" -msgstr "修改設定的遠端" +msgstr "修改設定的遠端站點" #. TRANSLATORS: command description msgid "Monitor the daemon for events" @@ -435,11 +553,22 @@ msgstr "監控幕後程式是否有活動" msgid "Name" msgstr "名稱" +msgid "No action specified!" +msgstr "未指定動作!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "未偵測到具備韌體更新能力的硬體" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "找不到插件" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "目前沒有啟用的遠端站點,因而沒有中介資料可用。" + msgid "OK" msgstr "確定" @@ -447,6 +576,10 @@ msgstr "確定" msgid "Override plugin warning" msgstr "凌駕插件警告" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "凌駕預設 ESP 路徑" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "密碼" @@ -473,6 +606,10 @@ msgstr "繼續上傳?" msgid "Protocol" msgstr "協定" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "查詢韌體更新支援" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -503,7 +640,7 @@ msgstr "地區" #. * e.g. "1.2.3" #, c-format msgid "Reinstalling %s with %s... " -msgstr "正重新安裝 %s %s 版…" +msgstr "正將 %s 重新安裝為 %s 版... " #. TRANSLATORS: section header for the remote the file is coming from msgid "Remote" @@ -580,6 +717,10 @@ msgstr "設定韌體檔案產品 ID" msgid "Set release version on firmware file" msgstr "設定韌體檔案發行版本" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "在更新期間設定除錯旗標" + #. TRANSLATORS: command description msgid "Set the firmware size for the target" msgstr "設定目標的韌體檔案大小" @@ -608,6 +749,10 @@ msgstr "顯示所有檔案的除錯資訊" msgid "Show debugging options" msgstr "顯示除錯選項" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "顯示不可更新的裝置" + #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "顯示額外除錯資訊" @@ -620,6 +765,14 @@ msgstr "顯示韌體更新的歷史" msgid "Show plugin verbose information" msgstr "顯示插件詳盡資訊" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "顯示從上次試圖更新起的除錯紀錄" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "顯示韌體更新狀態的資訊" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "狀態" @@ -637,12 +790,27 @@ msgstr "摘要" msgid "Target" msgstr "目標" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS(Linux 廠商韌體服務,Linux Vendor Firmware Service)是由獨立法人運作的免費服務,而與 $OS_RELEASE:NAME$ 沒有關聯。您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。所有本服務中的韌體僅由原始設備製造商提供。" + msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." msgstr "fwupd 程序是個簡易幕後程式,允許工作階段軟體更新您本地端機器上的裝置韌體。它主要設計給桌面電腦使用,但本專案也能用於手機、平板,或是指令列介面伺服器。" +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "更新必須重新開機才能完成。" + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "此程式僅有 root 身份才能正常運作" + msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." msgstr "本專案宗旨在於讓 Linux 上的韌體更新能自動、安全、可靠。您可以使用圖形介面的軟體管理員,如《GNOME 軟體》來檢視並套用更新,或用指令列工具,或甚至直接用 D-Bus 介面。" +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "這個遠端站點包含未列入禁運,但仍處於硬體廠商測試階段的韌體。您應該確保自己在韌體更新失敗時有方法能夠手動降級韌體。" + #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "標題" @@ -655,6 +823,10 @@ msgstr "傳輸大小" msgid "Type" msgstr "類型" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI 韌體公用程式" + #. TRANSLATORS: section header for firmware URI msgid "URI" msgstr "URI" @@ -670,6 +842,10 @@ msgstr "解鎖裝置以允許存取" msgid "Unlocks the device for firmware access" msgstr "解鎖裝置以供韌體存取" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "取消更新期間的除錯旗標設定" + #. TRANSLATORS: section header for firmware checksum msgid "Update Checksum" msgstr "更新校驗計算碼" @@ -725,7 +901,7 @@ msgstr "將所有韌體更新至可用的最新版本" #. * version numbers e.g. "1.2.3" #, c-format msgid "Updating %s from %s to %s... " -msgstr "正更新 %s 從 %s 版至 %s 版…" +msgstr "正將 %s 從 %s 版升級至 %s 版... " #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" @@ -735,6 +911,10 @@ msgstr "上傳訊息:" msgid "Upload report now?" msgstr "是否立刻上傳報告?" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "上傳韌體報告可以協助硬體廠商快速辨識出更新作業在真實裝置上是失敗還成功。" + #. TRANSLATORS: remote filename base msgid "Username" msgstr "使用者名稱" @@ -755,6 +935,10 @@ msgstr "等候中…" msgid "Watch DFU devices being hotplugged" msgstr "監看 DFU 裝置熱插拔的過程" +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "監看硬體是否有變更" + #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "從檔案將韌體寫入裝置" @@ -767,5 +951,9 @@ msgstr "從檔案將韌體寫入一分割區" msgid "Writing…" msgstr "寫入中…" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。" + msgid "fwupd" msgstr "fwupd" From 258aab19fa5dc8ab9a6065e3a7a1f94d808ef3f1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Nov 2018 11:25:11 +0000 Subject: [PATCH 060/254] trivial: post release version bump --- RELEASE | 8 ++++---- meson.build | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/RELEASE b/RELEASE index 68ae8f76e..5b9b6224e 100644 --- a/RELEASE +++ b/RELEASE @@ -2,9 +2,9 @@ fwupd Release Notes 1. Write NEWS entries for fwupd in the same format as usual. -git shortlog 1.1.2.. | grep -i -v trivial | grep -v Merge > NEWS.new +git shortlog 1.2.0.. | grep -i -v trivial | grep -v Merge > NEWS.new -Version 1.2.0 +Version 1.2.1 ~~~~~~~~~~~~~ Released: 2018-xx-xx @@ -23,8 +23,8 @@ git add ../po/*.po 2. Commit changes to git: -# MAKE SURE THESE ARE CORRECT -export release_ver="1.2.0" +# MAKE SURE THIS IS CORRECT +export release_ver="1.2.1" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/meson.build b/meson.build index 737841f1a..89480c997 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.2.0', + version : '1.2.1', license : 'LGPL-2.1+', meson_version : '>=0.46.0', default_options : ['warning_level=2', 'c_std=c99'], From 7cff2dcb25e4503cbf077744e4aa5a930371f4ae Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 7 Nov 2018 11:39:13 -0600 Subject: [PATCH 061/254] trivial: Bump meson dependency to 0.47.0 The current libxmlb dependency requires this and when run in subproject mode will cause failures otherwise. Also bump the snap to use meson 0.47.2 to fix snap build due to this failure. --- contrib/snap/snapcraft-master.yaml | 2 +- meson.build | 2 +- snap/snapcraft.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/snap/snapcraft-master.yaml b/contrib/snap/snapcraft-master.yaml index c443ae055..8149df842 100644 --- a/contrib/snap/snapcraft-master.yaml +++ b/contrib/snap/snapcraft-master.yaml @@ -71,7 +71,7 @@ parts: meson: plugin: python source: https://github.com/mesonbuild/meson.git - source-tag: 0.46.1 + source-tag: 0.47.2 build-packages: - ninja-build prime: diff --git a/meson.build b/meson.build index 89480c997..89cb408c9 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('fwupd', 'c', version : '1.2.1', license : 'LGPL-2.1+', - meson_version : '>=0.46.0', + meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], ) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index ad7659eea..51bc5f39f 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -68,7 +68,7 @@ parts: - -lib/*.a meson: plugin: python - source: https://github.com/mesonbuild/meson/releases/download/0.46.1/meson-0.46.1.tar.gz + source: https://github.com/mesonbuild/meson/releases/download/0.47.2/meson-0.47.2.tar.gz build-packages: - ninja-build prime: From 53a049fce88ab2f69c0e9056820196461b729110 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 7 Nov 2018 12:29:04 +0000 Subject: [PATCH 062/254] trivial: Sync example spec file with downstream --- contrib/fwupd.spec.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 507f0d294..d7e616e5d 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -149,8 +149,10 @@ Data files for installed tests. %endif %if 0%{?have_uefi} -Dplugin_uefi=true \ + -Dplugin_nvme=true \ %else -Dplugin_uefi=false \ + -Dplugin_nvme=false \ %endif %if 0%{?have_dell} -Dplugin_dell=true \ @@ -265,12 +267,14 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_ebitdo.so %{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so %{_libdir}/fwupd-plugins-3/libfu_plugin_nitrokey.so +%if 0%{?have_uefi} %{_libdir}/fwupd-plugins-3/libfu_plugin_nvme.so +%endif %if 0%{?have_redfish} %{_libdir}/fwupd-plugins-3/libfu_plugin_redfish.so +%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_rts54hid.so %{_libdir}/fwupd-plugins-3/libfu_plugin_rts54hub.so -%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_steelseries.so %{_libdir}/fwupd-plugins-3/libfu_plugin_superio.so %if 0%{?have_dell} From ba2f0ae1d4f55bbb349971b44ee3d3c2b3774b7e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 8 Nov 2018 17:12:31 +0000 Subject: [PATCH 063/254] trivial: Document the GUID generation scheme Fixes https://github.com/hughsie/fwupd/issues/837 --- plugins/altos/README.md | 9 +++++++++ plugins/amt/README.md | 5 +++++ plugins/colorhug/README.md | 9 +++++++++ plugins/dell-dock/README.md | 12 ++++++++++++ plugins/dell-esrt/README.md | 5 +++++ plugins/dell/README.md | 10 ++++++++++ plugins/dfu/README.md | 9 +++++++++ plugins/ebitdo/README.md | 9 +++++++++ plugins/flashrom/README.md | 7 +++++++ plugins/nitrokey/README.md | 9 +++++++++ plugins/nvme/README.md | 16 ++++++++++++++++ plugins/redfish/README.md | 6 ++++++ plugins/rts54hid/README.md | 13 +++++++++++++ plugins/rts54hub/README.md | 8 ++++++++ plugins/steelseries/README.md | 9 +++++++++ plugins/superio/README.md | 7 +++++++ plugins/synapticsmst/README.md | 10 ++++++++++ plugins/test/README.md | 6 ++++++ plugins/thunderbolt/README.md | 12 ++++++++++++ plugins/udev/README.md | 9 +++++++++ plugins/uefi/README.md | 9 +++++++++ plugins/unifying/README.md | 14 ++++++++++++++ plugins/wacomhid/README.md | 9 +++++++++ 23 files changed, 212 insertions(+) diff --git a/plugins/altos/README.md b/plugins/altos/README.md index 4b3a3c272..d683807ed 100644 --- a/plugins/altos/README.md +++ b/plugins/altos/README.md @@ -15,6 +15,15 @@ The bootloader communication is not handled in the kernel, and a tty device is created so userspace can communicate with the hardware. Commands the bootloader accept are as follows: +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_1D50&PID_60C6&REV_0001` + * `USB\VID_1D50&PID_60C6` + * `USB\VID_1D50` + ### List Information Command: `l\n` diff --git a/plugins/amt/README.md b/plugins/amt/README.md index 4a053b229..5494815a4 100644 --- a/plugins/amt/README.md +++ b/plugins/amt/README.md @@ -15,3 +15,8 @@ which can be found here: https://github.com/mjg59/mei-amt-check That tool in turn is heavily based on mei-amt-version from samples/mei in the Linux source tree and copyright Intel Corporation. + +GUID Generation +--------------- + +These devices use the existing GUID provided by the AMT host interface. diff --git a/plugins/colorhug/README.md b/plugins/colorhug/README.md index 06eae25d1..867d03dae 100644 --- a/plugins/colorhug/README.md +++ b/plugins/colorhug/README.md @@ -10,3 +10,12 @@ accurate color matching. ColorHug versions 1 and 2 support a custom HID-based flashing protocol, but version 3 (ColorHug+) has now switched to DFU. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_273F&PID_1001&REV_0001` + * `USB\VID_273F&PID_1001` + * `USB\VID_273F` diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index 101ba4332..d896717a4 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -4,6 +4,18 @@ Dell USB-C Dock ### Dell System Unlike previous Dell USB-C devices, a Dell system is not needed for updating. +GUID Generation +--------------- + +These devices use several different generation schemes, e.g. + + * USB Hub1: `USB\VID_413C&PID_B06F&hub` + * USB Hub2: `USB\VID_413C&PID_B06E&hub` + * Embedded Controller: `USB\VID_413C&PID_B06E&hub&embedded` + * Update Level: `USB\VID_413C&PID_B06E&hub&status` + * MST Hub: `MST-panamera-vmm5331-259` + * Thunderbolt Controller: `TBT-00d4b070` + ### Components The device contains components the following directly updatable components: * USB hubs diff --git a/plugins/dell-esrt/README.md b/plugins/dell-esrt/README.md index 0a0f9dd68..797558a14 100644 --- a/plugins/dell-esrt/README.md +++ b/plugins/dell-esrt/README.md @@ -7,6 +7,11 @@ Introduction This allows enabling the BIOS setup option for UEFI capsule updates without manually going into BIOS setup. +GUID Generation +--------------- + +These device uses a hardcoded GUID of `2d47f29b-83a2-4f31-a2e8-63474f4d4c2e`. + Build Requirements ------------------ diff --git a/plugins/dell/README.md b/plugins/dell/README.md index 292b64688..eb54bcfa0 100644 --- a/plugins/dell/README.md +++ b/plugins/dell/README.md @@ -6,6 +6,16 @@ Introduction This allows installing Dell capsules that are not part of the ESRT table. +GUID Generation +--------------- + +These devices uses custom GUIDs for Dell-specific hardware. + + * Thunderbolt devices: `TBT-0x00d4u$(system-id)` + * TPM devices `$(system-id)-$(mode)`, where `mode` is either `2.0` or `1.2` + +In both cases the `system-id` is derived from the SMBIOS Product SKU property. + Build Requirements ------------------ diff --git a/plugins/dfu/README.md b/plugins/dfu/README.md index 4a408f90a..5a8e5d90d 100644 --- a/plugins/dfu/README.md +++ b/plugins/dfu/README.md @@ -6,3 +6,12 @@ Introduction Device Firmware Update is a standard that allows USB devices to be easily and safely updated by any operating system. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_273F&PID_1003&REV_0001` + * `USB\VID_273F&PID_1003` + * `USB\VID_273F` diff --git a/plugins/ebitdo/README.md b/plugins/ebitdo/README.md index 8fe729bcd..157e77623 100644 --- a/plugins/ebitdo/README.md +++ b/plugins/ebitdo/README.md @@ -11,3 +11,12 @@ library and is possible thanks to the vendor open sourcing the flashing tool. The 8Bitdo devices share legacy USB VID/PIDs with other projects and so we have to be a bit careful to not claim other devices as our own. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_2DC8&PID_AB11&REV_0001` + * `USB\VID_2DC8&PID_AB11` + * `USB\VID_2DC8` diff --git a/plugins/flashrom/README.md b/plugins/flashrom/README.md index 4df977c38..a65bc9104 100644 --- a/plugins/flashrom/README.md +++ b/plugins/flashrom/README.md @@ -5,3 +5,10 @@ Introduction ------------ This plugin uses `flashrom` to update the system firmware. + +GUID Generation +--------------- + +These device uses hardware ID values which are derived from SMBIOS. They should +match the values provided by `fwupdtool hwids` or the `ComputerHardwareIds.exe` +Windows utility. diff --git a/plugins/nitrokey/README.md b/plugins/nitrokey/README.md index fa01fd052..df0151ea9 100644 --- a/plugins/nitrokey/README.md +++ b/plugins/nitrokey/README.md @@ -10,3 +10,12 @@ available from the vendor. The device is switched to a DFU bootloader only when the secret firmware pin is entered into the nitrokey-app tool. This cannot be automated. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_20A0&PID_4109&REV_0001` + * `USB\VID_20A0&PID_4109` + * `USB\VID_20A0` diff --git a/plugins/nvme/README.md b/plugins/nvme/README.md index dd189dea0..ca6685d8c 100644 --- a/plugins/nvme/README.md +++ b/plugins/nvme/README.md @@ -10,3 +10,19 @@ firmware file. Firmware is sent in 4kB chunks and activated on next reboot. The device GUID is read from the vendor specific area and if not found then generated from the trimmed model string. + +GUID Generation +--------------- + +These device use the NVMe DeviceInstanceId values, e.g. + + * `NVME\VEN_1179&DEV_010F&REV_01` + * `NVME\VEN_1179&DEV_010F` + * `NVME\VEN_1179` + +Additionally, for NVMe drives with Dell vendor firmware two extra GUIDs are +added: + + * `STORAGE-DELL-${component-id}` + +and any optional GUID saved in the vendor extension block. diff --git a/plugins/redfish/README.md b/plugins/redfish/README.md index a27563599..217a42151 100644 --- a/plugins/redfish/README.md +++ b/plugins/redfish/README.md @@ -10,6 +10,12 @@ simple and secure management of modern scalable platform hardware. By specifying a RESTful interface and utilizing JSON and OData, Redfish helps customers integrate solutions within their existing tool chains. +GUID Generation +--------------- + +These devices use the provided GUID provided in the `SoftwareId` parameter +without modification. Devices without GUIDs are not supported. + Setting Service IP Manually --------------------------- diff --git a/plugins/rts54hid/README.md b/plugins/rts54hid/README.md index 835dc9b29..9ea488829 100644 --- a/plugins/rts54hid/README.md +++ b/plugins/rts54hid/README.md @@ -10,3 +10,16 @@ device using the HUB update protocol. Other devices connected to the RTS54HIDxx using I2C will be supported soon. +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0BDA&PID_1100&REV_0001` + * `USB\VID_0BDA&PID_1100` + * `USB\VID_0BDA` + +Child I²C devices are created using the device number as a suffix, for instance: + + * `USB\VID_0BDA&PID_1100&I2C_01` + diff --git a/plugins/rts54hub/README.md b/plugins/rts54hub/README.md index 85c3e3d91..dd17cbc5a 100644 --- a/plugins/rts54hub/README.md +++ b/plugins/rts54hub/README.md @@ -10,3 +10,11 @@ device using the HID update protocol. Other devices connected to the RTS54xx using I2C will be supported soon. +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0BDA&PID_5423&REV_0001` + * `USB\VID_0BDA&PID_5423` + * `USB\VID_0BDA` diff --git a/plugins/steelseries/README.md b/plugins/steelseries/README.md index 314feffef..1266c6f6d 100644 --- a/plugins/steelseries/README.md +++ b/plugins/steelseries/README.md @@ -7,3 +7,12 @@ Introduction This plugin is used to get the correct version number on SteelSeries gaming mice. These mice have updatable firmware but so far no updates are available from the vendor. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_1038&PID_1702&REV_0001` + * `USB\VID_1038&PID_1702` + * `USB\VID_1038` diff --git a/plugins/superio/README.md b/plugins/superio/README.md index c6c89f002..3be1ae935 100644 --- a/plugins/superio/README.md +++ b/plugins/superio/README.md @@ -20,3 +20,10 @@ Other useful links: * https://github.com/coreboot/coreboot/blob/master/util/superiotool/superiotool.h * https://github.com/flashrom/flashrom/blob/master/it85spi.c * http://wiki.laptop.org/go/Ec_specification + +GUID Generation +--------------- + +These devices use a custom GUID generated using the SuperIO chipset name: + + * `SuperIO-$(chipset)`, for example `SuperIO-IT8512` diff --git a/plugins/synapticsmst/README.md b/plugins/synapticsmst/README.md index e50a7c996..b32fa46b1 100644 --- a/plugins/synapticsmst/README.md +++ b/plugins/synapticsmst/README.md @@ -3,6 +3,16 @@ This plugin supports querying and flashing Synaptics MST hubs used in Dell systems and docks. +GUID Generation +--------------- + +These devices use custom GUID values, e.g. + + * `MST-$(device_kind)-$(chip-ID)-$(board-ID)` + +Please refer to the plugin source for more details about how the GUID is +constructed for specific hardware. + ## Requirements ### (Kernel) DP Aux Interface Kernel 4.6 introduced an DRM DP Aux interface for manipulation of the registers diff --git a/plugins/test/README.md b/plugins/test/README.md index bef15c829..4c8891cfb 100644 --- a/plugins/test/README.md +++ b/plugins/test/README.md @@ -5,3 +5,9 @@ Introduction ------------ This plugin is used when running the self tests in the fwupd project. + +GUID Generation +--------------- + +The devices created by this plugin use hardcoded GUIDs that do not correspond +to any kind of DeviceInstanceId values. diff --git a/plugins/thunderbolt/README.md b/plugins/thunderbolt/README.md index 5ceeca54d..7757f5b1d 100644 --- a/plugins/thunderbolt/README.md +++ b/plugins/thunderbolt/README.md @@ -9,6 +9,18 @@ allows the connection of external peripherals to a computer. Versions 1 and 2 use the same connector as Mini DisplayPort (MDP), whereas version 3 uses USB Type-C. +GUID Generation +--------------- + +These devices use a custom GUID generation scheme. +When the device is in "safe mode" the GUID is hardcoded using: + + * `TBT-safemode` + +... and when in runtime mode the GUID is: + + * `TBT-$(vid)$(pid)-native` when native, and `TBT-$(vid)$(pid)` otherwise. + Runtime Power Management ------------------------ diff --git a/plugins/udev/README.md b/plugins/udev/README.md index cf254bc4e..994769762 100644 --- a/plugins/udev/README.md +++ b/plugins/udev/README.md @@ -10,3 +10,12 @@ require booting into another operating system to apply. This plugin is also able to read and parse the firmware of some PCI devices which allows some host state verification to be done. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `PCI\VEN_%04X&DEV_%04X` + +Additionally, GUIDs found in OptionROMs may also be added. diff --git a/plugins/uefi/README.md b/plugins/uefi/README.md index c005abf7f..7082bc9eb 100644 --- a/plugins/uefi/README.md +++ b/plugins/uefi/README.md @@ -11,6 +11,15 @@ With the UpdateCapsule boot service it can be used to update system firmware. If you don't want or need this functionality you can use the `-Dplugin_uefi=false` option. +GUID Generation +--------------- + +These devices use the UEFI GUID as provided in the ESRT. Additionally, for the +system device the `main-system-firmware` GUID is also added. + +For compatibility with Windows 10, the plugin also adds GUIDs of the form +`UEFI\RES_{$(esrt)}`. + UEFI Unlock Support ------------------- diff --git a/plugins/unifying/README.md b/plugins/unifying/README.md index 94c255d13..e724da15d 100644 --- a/plugins/unifying/README.md +++ b/plugins/unifying/README.md @@ -16,6 +16,20 @@ supplied by Logitech. Additional constants were taken from the Solaar[2] project. +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values when in DFU mode: + + * `USB\VID_046D&PID_AAAA&REV_0001` + * `USB\VID_046D&PID_AAAA` + * `USB\VID_046D` + +When in runtime mode, the HID raw DeviceInstanceId values are used: + + * `HIDRAW\VEN_046D&DEV_C52B` + * `HIDRAW\VEN_046D` + Design Notes ------------ diff --git a/plugins/wacomhid/README.md b/plugins/wacomhid/README.md index 69758aff2..8e01ec53b 100644 --- a/plugins/wacomhid/README.md +++ b/plugins/wacomhid/README.md @@ -15,3 +15,12 @@ Wacom devices are actually composite devices, with the main ARM CPU being programmed using a more complicated erase, write, verify algorithm based on a historical update protocol. The "sub-module" devices use a newer protocol, again based on HID, but are handled differently depending on thier type. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_056A&PID_0378&REV_0001` + * `USB\VID_056A&PID_0378` + * `USB\VID_056A` From 42111a3880131966304f4614179c655c07b56f69 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 8 Nov 2018 20:05:12 +0000 Subject: [PATCH 064/254] trivial: Relax the timing requirements on the FuDevice poll test If the poll source is scheduled just at the right time, we might only get 8x '10ms ticks' in a 100ms window. This fixes an occasional build failure on slower hardware and in CI. --- src/fu-self-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 3c774b558..edc0088db 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -2806,7 +2806,7 @@ fu_device_poll_func (void) fu_test_loop_run_with_timeout (100); fu_test_loop_quit (); cnt = fu_device_get_metadata_integer (device, "cnt"); - g_assert_cmpint (cnt, >=, 9); + g_assert_cmpint (cnt, >=, 8); /* disable the poll */ fu_device_set_poll_interval (device, 0); From 9636f280957484882fe3f908359469a4076dedcf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 8 Nov 2018 20:38:47 +0000 Subject: [PATCH 065/254] trivial: Drop the libxmlb insertion into the flathub manifest The 1.2.0 release is being built in Flathub now. --- contrib/ci/flatpak.py | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/contrib/ci/flatpak.py b/contrib/ci/flatpak.py index 6e494ad5f..ee8ec0272 100755 --- a/contrib/ci/flatpak.py +++ b/contrib/ci/flatpak.py @@ -25,15 +25,11 @@ def prepare (target): #update to build from master data["branch"] = "master" - has_libxmlb = False for index in range(0, num_modules): module = data['modules'][index] if type (module) != dict or not 'name' in module: continue name = module['name'] - if 'libxmlb' in name: - has_libxmlb = True - continue if not 'fwupd' in name: continue data['modules'][index]['sources'][0].pop ('url') @@ -42,27 +38,6 @@ def prepare (target): data['modules'][index]['sources'][0]['skip'] = [".git"] data['modules'][index]['sources'][0]['path'] = ".." - #add libxmlb (This should be dropped when new release to flathub) - if not has_libxmlb: - print ("Adding libxmlb into json") - libxmlb = {'name': 'libxmlb', - 'buildsystem': 'meson', - 'config-opts': [ - "-Dintrospection=false", - "-Dgtkdoc=false", - "-Dtests=false", - "--sysconfdir=/app/etc", - "--localstatedir=/var/data" - ], - 'cleanup': ['/libexec/xb-tool'], - 'sources': [{ - "type": "archive", - "url": "https://people.freedesktop.org/~hughsient/releases/libxmlb-0.1.3.tar.xz", - "sha256": "b609a95d078ab956231a43fd082382b386ed2f90e3fe5e8b785c4278a1b4787e" - }] - } - data['modules'].insert(num_modules-1, libxmlb) - #write json os.mkdir('build') with open (target, 'w') as wfd: From 4039001d25a8ecee7b5b870d794829100baa0949 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 9 Nov 2018 08:33:17 -0600 Subject: [PATCH 066/254] trivial: ci: fix flatpak build The submodules need to checkout the latest remote commit, not the latest one that was recorded by git metadata. --- contrib/ci/flatpak.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/ci/flatpak.py b/contrib/ci/flatpak.py index ee8ec0272..91aa2bfa1 100755 --- a/contrib/ci/flatpak.py +++ b/contrib/ci/flatpak.py @@ -6,11 +6,11 @@ import shutil def prepare (target): #clone the flatpak json - cmd = ['git', 'submodule', 'update', 'contrib/flatpak'] + cmd = ['git', 'submodule', 'update', '--remote', 'contrib/flatpak'] subprocess.run (cmd, check=True) #clone the submodules for that - cmd = ['git', 'submodule', 'update', '--init', 'shared-modules/'] + cmd = ['git', 'submodule', 'update', '--init', '--remote', 'shared-modules/'] subprocess.run (cmd, cwd='contrib/flatpak', check=True) #parse json From 33171fd24daa5faed25a07969d17ac1d37b1ebad Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 9 Nov 2018 13:29:11 +0000 Subject: [PATCH 067/254] trivial: Store the AppStream component metadata correctly We want the XML to look like: lvfs not: lvfs Also, fix the XPath query string to actually match the container checksum, and actually save the custom node to the builder source. This fixes a regression in 1.2.0 where no reports could be uploaded. --- src/fu-engine.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index d9af7773e..f9b3ea42e 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -293,7 +293,7 @@ fu_engine_set_release_from_appstream (FuEngine *self, fwupd_release_set_version (rel, version_rel); /* find the remote */ - remote_id = xb_node_query_text (component, "../custom/fwupd::RemoteId", NULL); + 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_config_get_remote_by_id (self->config, remote_id); @@ -341,10 +341,9 @@ fu_engine_get_remote_id_for_checksum (FuEngine *self, const gchar *csum) { g_autofree gchar *xpath = NULL; g_autoptr(XbNode) key = NULL; - xpath = g_build_filename ("components", "component", "releases", "release", - "checksum[@target='container']", "..", "..", - "..", "..", "custom", "fwupd::RemoteId", NULL); - + xpath = g_strdup_printf ("components/component/releases/release/" + "checksum[@target='container'][text()='%s']/../../" + "../../custom/value[@key='fwupd::RemoteId']", csum); key = xb_silo_query_first (self->silo, xpath, NULL); if (key == NULL) return NULL; @@ -1810,13 +1809,6 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) } /* save the remote-id in the custom metadata space */ - custom = xb_builder_node_new ("custom"); - xb_builder_node_insert_text (custom, - "fwupd::FilenameCache", path, - NULL); - xb_builder_node_insert_text (custom, - "fwupd::RemoteId", fwupd_remote_get_id (remote), - NULL); file = g_file_new_for_path (path); if (!xb_builder_source_load_file (source, file, XB_BUILDER_SOURCE_FLAG_NONE, @@ -1827,6 +1819,18 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) continue; } + /* add metadata */ + custom = xb_builder_node_new ("custom"); + xb_builder_node_insert_text (custom, + "value", path, + "key", "fwupd::FilenameCache", + NULL); + xb_builder_node_insert_text (custom, + "value", fwupd_remote_get_id (remote), + "key", "fwupd::RemoteId", + NULL); + xb_builder_source_set_info (source, custom); + /* we need to watch for changes? */ xb_builder_import_source (builder, source); } From 3b743402f54c7812a947ae21f3d4550ffb8a4b86 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 9 Nov 2018 13:34:10 +0000 Subject: [PATCH 068/254] Include the os-release information in the release metadata This means we are storing the distro that was used to perform the update, rather than the distro that was used to do the upload. Fixes https://github.com/hughsie/fwupd/issues/838 --- src/fu-engine.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index f9b3ea42e..40b25d6a9 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1421,8 +1421,14 @@ fu_engine_install_blob (FuEngine *self, g_autoptr(FwupdRelease) release_history = fwupd_release_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GHashTable) metadata_hash = NULL; + g_autoptr(GHashTable) os_release = NULL; g_autoptr(GTimer) timer = g_timer_new (); + /* add release data from os-release */ + os_release = fwupd_get_os_release (error); + if (os_release == NULL) + return FALSE; + /* test the firmware is not an empty blob */ if (g_bytes_get_size (blob_fw2) == 0) { g_set_error (error, @@ -1491,11 +1497,29 @@ fu_engine_install_blob (FuEngine *self, /* add device to database */ if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0) { + const gchar *tmp; g_autofree gchar *checksum = NULL; checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob_cab); fwupd_release_set_version (release_history, version); fwupd_release_add_checksum (release_history, checksum); fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + + /* add details from os-release as metadata */ + tmp = g_hash_table_lookup (os_release, "ID"); + if (tmp != NULL) { + fwupd_release_add_metadata_item (release_history, + "DistroId", tmp); + } + tmp = g_hash_table_lookup (os_release, "VERSION_ID"); + if (tmp != NULL) { + fwupd_release_add_metadata_item (release_history, + "DistroVersion", tmp); + } + tmp = g_hash_table_lookup (os_release, "VARIANT_ID"); + if (tmp != NULL) { + fwupd_release_add_metadata_item (release_history, + "DistroVariant", tmp); + } if (!fu_history_add_device (self->history, device, release_history, error)) return FALSE; } From 0393f6fa8147cc79ce97f8e96412d3a8c58d8747 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 9 Nov 2018 13:37:38 +0000 Subject: [PATCH 069/254] Be more explicit setting the update state If the FuDevice is changed during a replug then the `UPDATE_STATE_SUCCESS` will not be stored on the current FuDevice, which means we store an update-state of `unknown` to the history database. Which means we get no success or failure reports, which is bad. --- src/fu-engine.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 40b25d6a9..98647b25b 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1526,6 +1526,7 @@ fu_engine_install_blob (FuEngine *self, /* do the update */ if (!fu_plugin_runner_update_detach (plugin, device, &error_local)) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); fu_device_set_update_error (device, error_local->message); if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && !fu_history_modify_device (self->history, device, @@ -1561,6 +1562,7 @@ fu_engine_install_blob (FuEngine *self, g_autoptr(GError) error_attach = NULL; /* save to database */ + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); fu_device_set_update_error (device, error_local->message); if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && !fu_history_modify_device (self->history, device, @@ -1609,6 +1611,7 @@ fu_engine_install_blob (FuEngine *self, return FALSE; } if (!fu_plugin_runner_update_attach (plugin, device, &error_local)) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); fu_device_set_update_error (device, error_local->message); if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && !fu_history_modify_device (self->history, device, @@ -1675,6 +1678,7 @@ fu_engine_install_blob (FuEngine *self, if (version != NULL && g_strcmp0 (version_orig, version) != 0 && g_strcmp0 (version_orig, fu_device_get_version (device)) == 0) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); fu_device_set_update_error (device, "device version not updated on success"); if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && !fu_history_modify_device (self->history, device, @@ -1694,12 +1698,12 @@ fu_engine_install_blob (FuEngine *self, } /* success */ + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && !fu_history_modify_device (self->history, device, FU_HISTORY_FLAGS_MATCH_NEW_VERSION, error)) return FALSE; - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); return TRUE; } From fdcec2c6e8aaed5074d0aee1edf276b493eb39ce Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 9 Nov 2018 13:51:21 +0000 Subject: [PATCH 070/254] trivial: Only include a single language in the metainfo silo Return the warnings in the C locale like we did with appstream-glib. --- src/fu-config.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fu-config.c b/src/fu-config.c index 471bf709c..a803a8bd3 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -449,6 +449,7 @@ fu_config_load_metainfos (XbBuilder *builder, GError **error) gboolean fu_config_load (FuConfig *self, GError **error) { + const gchar *const *locales = g_get_language_names (); g_autofree gchar *configdir = NULL; g_autofree gchar *config_file = NULL; g_autofree gchar *cachedirpkg = NULL; @@ -475,11 +476,16 @@ fu_config_load (FuConfig *self, GError **error) if (!fu_config_load_metainfos (builder, error)) return FALSE; + /* add the locales, which is really only going to be 'C' or 'en' */ + for (guint i = 0; locales[i] != NULL; i++) + xb_builder_add_locale (builder, locales[i]); + /* build the metainfo silo */ cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); xmlbfn = g_build_filename (cachedirpkg, "metainfo.xmlb", NULL); xmlb = g_file_new_for_path (xmlbfn); self->silo = xb_builder_ensure (builder, xmlb, + XB_BUILDER_COMPILE_FLAG_SINGLE_LANG | XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID, NULL, error); if (self->silo == NULL) From 1985b706b9bd1bcf8acd7361db5ce07633461f7c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 9 Nov 2018 13:53:14 +0000 Subject: [PATCH 071/254] Fix showing the custom remote agreements This fixes a regression in 1.2.0 -- the XML files are metainfo.xml files and thus don't have the surrounding parent tag. We also want to return XML without the wrapper node, so switch to including siblings instead. --- src/fu-config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fu-config.c b/src/fu-config.c index a803a8bd3..f3cad88aa 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -139,7 +139,7 @@ fu_config_get_remote_agreement_for_app (FwupdRemote *self, XbNode *component, GE g_autoptr(GError) error_local = NULL; /* manually find the first agreement section */ - n = xb_node_query_first (component, "agreement/agreement_section/description", &error_local); + n = xb_node_query_first (component, "agreement/agreement_section/description/*", &error_local); if (n == NULL) { g_set_error (error, FWUPD_ERROR, @@ -148,7 +148,7 @@ fu_config_get_remote_agreement_for_app (FwupdRemote *self, XbNode *component, GE error_local->message); return NULL; } - tmp = xb_node_export (n, XB_NODE_EXPORT_FLAG_NONE, error); + tmp = xb_node_export (n, XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS, error); if (tmp == NULL) return NULL; return g_string_new (tmp); @@ -207,7 +207,7 @@ fu_config_add_remotes_for_path (FuConfig *self, const gchar *path, GError **erro g_autoptr(XbNode) component = NULL; g_autofree gchar *xpath = NULL; - xpath = g_strdup_printf ("components/component/id[text()='%s']/..", component_id); + xpath = g_strdup_printf ("component/id[text()='%s']/..", component_id); component = xb_silo_query_first (self->silo, xpath, NULL); if (component != NULL) { agreement_markup = fu_config_get_remote_agreement_for_app (remote, component, error); From d56ad5b440f55139a05790d70f76198f28f800ae Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 12 Nov 2018 10:48:06 +0000 Subject: [PATCH 072/254] trivial: Fix a possible critical warning when parsing invalid metadata --- src/fu-engine.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 98647b25b..8cccdddcf 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2543,7 +2543,14 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er /* return the compound error */ if (releases->len == 0) { - g_propagate_error (error, g_steal_pointer (&error_all)); + if (error_all != NULL) { + g_propagate_error (error, g_steal_pointer (&error_all)); + return NULL; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No valid releases found for device"); return NULL; } return releases; From 26db91ba13a653fd747dd33e747fe7cc44ebc5cd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 12 Nov 2018 10:47:36 +0000 Subject: [PATCH 073/254] trivial: Create an empty tree before tests start This ensures we only load the files we actually write in the test. --- src/fu-self-test.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/fu-self-test.c b/src/fu-self-test.c index edc0088db..c5e739b6c 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -41,6 +41,17 @@ #include "fu-keyring-pkcs7.h" #endif +static void +fu_self_test_mkroot (void) +{ + if (g_file_test ("/tmp/fwupd-self-test", G_FILE_TEST_EXISTS)) { + g_autoptr(GError) error = NULL; + if (!fu_common_rmtree ("/tmp/fwupd-self-test", &error)) + g_warning ("failed to mkroot: %s", error->message); + } + g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); +} + static void fu_engine_requirements_missing_func (void) { @@ -539,6 +550,9 @@ fu_engine_downgrade_func (void) g_autoptr(GPtrArray) remotes = NULL; g_autoptr(XbSilo) silo_empty = xb_silo_new (); + /* ensure empty tree */ + fu_self_test_mkroot (); + /* no metadata in daemon */ fu_engine_set_silo (engine, silo_empty); @@ -694,8 +708,8 @@ fu_engine_history_func (void) g_autoptr(XbSilo) silo_empty = xb_silo_new (); g_autoptr(XbSilo) silo = NULL; - /* ensure the history database is fresh */ - g_unlink ("/tmp/fwupd-self-test/var/lib/fwupd/pending.db"); + /* ensure empty tree */ + fu_self_test_mkroot (); /* no metadata in daemon */ fu_engine_set_silo (engine, silo_empty); @@ -3084,8 +3098,8 @@ main (int argc, char **argv) g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR_SRC, TRUE); g_setenv ("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE); - fu_common_rmtree ("/tmp/fwupd-self-test", NULL); - g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); + /* ensure empty tree */ + fu_self_test_mkroot (); /* tests go here */ if (g_test_slow ()) From 6e0c8f874213b1fdfde63c544da92102fbd0b947 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 11 Nov 2018 21:46:41 +0000 Subject: [PATCH 074/254] Add per-release install duration values These are set from the AppStream metadata and are specific to the firmware release. If not provided, the install duration falls back to the per-device duration values which can be set in the quirk files. --- libfwupd/fwupd-release.c | 58 +++++++++++++++++++++++++++++++++ libfwupd/fwupd-release.h | 3 ++ libfwupd/fwupd.map | 7 ++++ src/fu-engine.c | 11 +++++-- src/fu-self-test.c | 69 ++++++++++++++++++++++++++++++++++++++++ src/fu-util.c | 49 ++++++++++++++++++++++++++++ 6 files changed, 195 insertions(+), 2 deletions(-) diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index eb765b7a3..aba345fff 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -43,6 +43,7 @@ typedef struct { gchar *version; gchar *remote_id; guint64 size; + guint32 install_duration; FwupdTrustFlags trust_flags; } FwupdReleasePrivate; @@ -641,6 +642,41 @@ fwupd_release_set_trust_flags (FwupdRelease *release, FwupdTrustFlags trust_flag priv->trust_flags = trust_flags; } +/** + * fwupd_release_get_install_duration: + * @release: A #FwupdRelease + * + * Gets the time estimate for firmware installation (in seconds) + * + * Returns: the estimated time to flash this release (or 0 if unset) + * + * Since: 1.2.1 + **/ +guint32 +fwupd_release_get_install_duration (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), 0); + return priv->install_duration; +} + +/** + * fwupd_release_set_install_duration: + * @release: A #FwupdRelease + * @duration: The amount of time + * + * Sets the time estimate for firmware installation (in seconds) + * + * Since: 1.2.1 + **/ +void +fwupd_release_set_install_duration (FwupdRelease *release, guint32 duration) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + priv->install_duration = duration; +} + static GVariant * _hash_kv_to_variant (GHashTable *hash) { @@ -770,6 +806,11 @@ fwupd_release_to_variant (FwupdRelease *release) FWUPD_RESULT_KEY_METADATA, _hash_kv_to_variant (priv->metadata)); } + if (priv->install_duration > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_INSTALL_DURATION, + g_variant_new_uint32 (priv->install_duration)); + } return g_variant_new ("a{sv}", &builder); } @@ -836,6 +877,10 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant fwupd_release_set_trust_flags (release, g_variant_get_uint64 (value)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) { + fwupd_release_set_install_duration (release, g_variant_get_uint32 (value)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { g_hash_table_unref (priv->metadata); priv->metadata = _variant_to_hash_kv (value); @@ -885,6 +930,18 @@ fwupd_pad_kv_tfl (GString *str, const gchar *key, FwupdTrustFlags trust_flags) fwupd_pad_kv_str (str, key, tmp->str); } +static void +fwupd_pad_kv_int (GString *str, const gchar *key, guint32 value) +{ + g_autofree gchar *tmp = NULL; + + /* ignore */ + if (value == 0) + return; + tmp = g_strdup_printf("%" G_GUINT32_FORMAT, value); + fwupd_pad_kv_str (str, key, tmp); +} + /** * fwupd_release_to_string: * @release: A #FwupdRelease @@ -922,6 +979,7 @@ fwupd_release_to_string (FwupdRelease *release) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR, priv->vendor); fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_TRUST_FLAGS, priv->trust_flags); + fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); diff --git a/libfwupd/fwupd-release.h b/libfwupd/fwupd-release.h index fad822511..60f6f99ab 100644 --- a/libfwupd/fwupd-release.h +++ b/libfwupd/fwupd-release.h @@ -84,6 +84,9 @@ void fwupd_release_set_license (FwupdRelease *release, FwupdTrustFlags fwupd_release_get_trust_flags (FwupdRelease *release); void fwupd_release_set_trust_flags (FwupdRelease *release, FwupdTrustFlags trust_flags); +guint32 fwupd_release_get_install_duration (FwupdRelease *release); +void fwupd_release_set_install_duration (FwupdRelease *release, + guint32 duration); G_END_DECLS diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 52ee9bd41..52aba25e7 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -279,3 +279,10 @@ LIBFWUPD_1.1.3 { fwupd_device_set_install_duration; local: *; } LIBFWUPD_1.1.2; + +LIBFWUPD_1.2.1 { + global: + fwupd_release_get_install_duration; + fwupd_release_set_install_duration; + local: *; +} LIBFWUPD_1.1.3; diff --git a/src/fu-engine.c b/src/fu-engine.c index 8cccdddcf..61c18e57f 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -332,6 +332,9 @@ fu_engine_set_release_from_appstream (FuEngine *self, fwupd_release_set_size (rel, *sizeptr); } } + tmp64 = xb_node_get_attr_as_uint (release, "install_duration"); + if (tmp64 != 0) + fwupd_release_set_install_duration (rel, tmp64); } /* finds the remote-id for the first firmware in the silo that matches this @@ -2092,7 +2095,7 @@ fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) } static FwupdDevice * -fu_engine_get_result_from_app (FuEngine *self, XbNode *component, GError **error) +fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError **error) { FwupdTrustFlags trust_flags = FWUPD_TRUST_FLAG_NONE; g_autoptr(FuInstallTask) task = NULL; @@ -2247,7 +2250,7 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) for (guint i = 0; i < components->len; i++) { XbNode *component = g_ptr_array_index (components, i); FwupdDevice *dev; - dev = fu_engine_get_result_from_app (self, component, error); + dev = fu_engine_get_result_from_component (self, component, error); if (dev == NULL) return NULL; if (remote_id != NULL) { @@ -2452,6 +2455,10 @@ fu_engine_add_releases_for_device_component (FuEngine *self, /* create new FwupdRelease for the XbNode */ fu_engine_set_release_from_appstream (self, rel, component, release); + /* fall back to quirk-provided value */ + if (fwupd_release_get_install_duration (rel) == 0) + fwupd_release_set_install_duration (rel, fu_device_get_install_duration (device)); + /* invalid */ if (fwupd_release_get_uri (rel) == NULL) continue; diff --git a/src/fu-self-test.c b/src/fu-self-test.c index c5e739b6c..c6f6c2179 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -684,6 +684,74 @@ fu_engine_downgrade_func (void) g_assert_cmpstr (fwupd_release_get_version (rel), ==, "1.2.2"); } +static void +fu_engine_install_duration_func (void) +{ + FwupdRelease *rel; + gboolean ret; + g_autofree gchar *testdatadir = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) releases = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* ensure empty tree */ + fu_self_test_mkroot (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* write the main file */ + ret = g_file_set_contents ("/tmp/fwupd-self-test/stable.xml", + "" + " " + " test" + " " + " aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + " " + " " + " " + " https://test.org/foo.cab" + " deadbeefdeadbeefdeadbeefdeadbeef" + " deadbeefdeadbeefdeadbeefdeadbeef" + " " + " " + " " + "", -1, &error); + g_assert_no_error (error); + g_assert (ret); + + testdatadir = fu_test_get_filename (TESTDATADIR, "."); + g_assert (testdatadir != NULL); + g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); + ret = fu_engine_load (engine, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add a device so we can get the install duration */ + fu_device_set_version (device, "1.2.3"); + fu_device_set_id (device, "test_device"); + fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + fu_device_set_install_duration (device, 999); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_engine_add_device (engine, device); + devices = fu_engine_get_devices (engine, &error); + g_assert_no_error (error); + g_assert (devices != NULL); + g_assert_cmpint (devices->len, ==, 1); + g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED)); + + /* check the release install duration */ + releases = fu_engine_get_releases (engine, fu_device_get_id (device), &error); + g_assert_no_error (error); + g_assert (releases != NULL); + g_assert_cmpint (releases->len, ==, 1); + rel = FWUPD_RELEASE (g_ptr_array_index (releases, 0)); + g_assert_cmpint (fwupd_release_get_install_duration (rel), ==, 120); +} + static void fu_engine_history_func (void) { @@ -3129,6 +3197,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/engine{requirements-device}", fu_engine_requirements_device_func); g_test_add_func ("/fwupd/engine{device-auto-parent}", fu_engine_device_parent_func); g_test_add_func ("/fwupd/engine{device-priority}", fu_engine_device_priority_func); + g_test_add_func ("/fwupd/engine{install-duration}", fu_engine_install_duration_func); g_test_add_func ("/fwupd/hwids", fu_hwids_func); g_test_add_func ("/fwupd/smbios", fu_smbios_func); g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); diff --git a/src/fu-util.c b/src/fu-util.c index c8176ee5c..20ced0c41 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1703,6 +1703,45 @@ fu_util_perhaps_refresh_remotes (FuUtilPrivate *priv, GError **error) return fu_util_download_metadata (priv, error); } +static gchar * +fu_util_time_to_str (guint64 tmp) +{ + g_return_val_if_fail (tmp != 0, FALSE); + + /* seconds */ + if (tmp < 60) { + /* TRANSLATORS: duration in seconds */ + return g_strdup_printf (ngettext ("%u second", "%u seconds", + (gint) tmp), + (guint) tmp); + } + + /* minutes */ + tmp /= 60; + if (tmp < 60) { + /* TRANSLATORS: duration in minutes */ + return g_strdup_printf (ngettext ("%u minute", "%u minutes", + (gint) tmp), + (guint) tmp); + } + + /* hours */ + tmp /= 60; + if (tmp < 60) { + /* TRANSLATORS: duration in minutes */ + return g_strdup_printf (ngettext ("%u hour", "%u hours", + (gint) tmp), + (guint) tmp); + } + + /* days */ + tmp /= 24; + /* TRANSLATORS: duration in days! */ + return g_strdup_printf (ngettext ("%u day", "%u days", + (gint) tmp), + (guint) tmp); +} + static gboolean fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1750,6 +1789,7 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) /* print all releases */ for (guint j = 0; j < rels->len; j++) { FwupdRelease *rel = g_ptr_array_index (rels, j); + guint64 duration; GPtrArray *checksums; /* TRANSLATORS: Appstream ID for the hardware type */ @@ -1769,6 +1809,15 @@ fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) fu_util_print_data (_("Update Remote ID"), fwupd_release_get_remote_id (rel)); + /* optional approximate duration */ + duration = fwupd_release_get_install_duration (rel); + if (duration > 0) { + g_autofree gchar *str = fu_util_time_to_str (duration); + /* TRANSLATORS: section header for the amount + * of time it takes to install the update */ + fu_util_print_data (_("Update Duration"), str); + } + checksums = fwupd_release_get_checksums (rel); for (guint k = 0; k < checksums->len; k++) { const gchar *checksum = g_ptr_array_index (checksums, k); From c7fe0a74537926db273701d43e936aa3466ebaef Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 9 Nov 2018 11:34:43 -0600 Subject: [PATCH 075/254] trivial: Add quirk documentation Fixes https://github.com/hughsie/lvfs-website/issues/192 --- plugins/dell-dock/README.md | 46 +++++--- plugins/dfu/README.md | 10 ++ plugins/nvme/README.md | 8 ++ plugins/rts54hid/README.md | 9 ++ src/README.md | 137 ++++++++++++++++++++++++ src/fu-quirks.h | 205 ------------------------------------ 6 files changed, 198 insertions(+), 217 deletions(-) create mode 100644 src/README.md diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index d896717a4..0c2cf1081 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -4,18 +4,6 @@ Dell USB-C Dock ### Dell System Unlike previous Dell USB-C devices, a Dell system is not needed for updating. -GUID Generation ---------------- - -These devices use several different generation schemes, e.g. - - * USB Hub1: `USB\VID_413C&PID_B06F&hub` - * USB Hub2: `USB\VID_413C&PID_B06E&hub` - * Embedded Controller: `USB\VID_413C&PID_B06E&hub&embedded` - * Update Level: `USB\VID_413C&PID_B06E&hub&status` - * MST Hub: `MST-panamera-vmm5331-259` - * Thunderbolt Controller: `TBT-00d4b070` - ### Components The device contains components the following directly updatable components: * USB hubs @@ -36,3 +24,37 @@ The MST controller is updated through either the DP Aux interface When this plugin is used, devices present in other plugins may be shown in the topology of this dock. This is intentional as this plugin works together with those plugins to manage the flashing of all components. + +GUID Generation +--------------- + +These devices use several different generation schemes, e.g. + + * USB Hub1: `USB\VID_413C&PID_B06F&hub` + * USB Hub2: `USB\VID_413C&PID_B06E&hub` + * Embedded Controller: `USB\VID_413C&PID_B06E&hub&embedded` + * Update Level: `USB\VID_413C&PID_B06E&hub&status` + * MST Hub: `MST-panamera-vmm5331-259` + * Thunderbolt Controller: `TBT-00d4b070` + +Custom flag use: +---------------- +This plugin uses the following plugin-specific custom flags: + +* `skip-restart`: Don't run the reset or reboot procedure of the component + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------------|-------------------------------------------------------------------------|-----------------------| +| `DellDockUnlockTarget` | The EC argument needed for unlocking certain device usage. | 1.1.3 | +| `DellDockBlobMajorOffset` | The offset of the major version number in a payload | 1.1.3 | +| `DellDockBlobMinorOffset` | The offset of the minor version number in a payload | 1.1.3 | +| `DellDockBlobBuildOffset` | The offset of the build version number in a payload | 1.1.3 | +| `DellDockBlobVersionOffset` | The offset of the ASCII representation of a version string in a payload | 1.1.3 | +| `DellDockBoardMin` | The minimum board revision required to safely operate the plugin | 1.1.3 | +| `DellDockVersionLowest` | The minimum component version required to safely operate the plugin | 1.1.3 | +| `DellDockBoard*` | The board description of a board revision | 1.1.3 | +| `DellDockInstallDurationI2C` | The duration of time required to install a payload via I2C. | 1.1.3 | diff --git a/plugins/dfu/README.md b/plugins/dfu/README.md index 5a8e5d90d..1f5690659 100644 --- a/plugins/dfu/README.md +++ b/plugins/dfu/README.md @@ -15,3 +15,13 @@ These devices use the standard USB DeviceInstanceId values, e.g. * `USB\VID_273F&PID_1003&REV_0001` * `USB\VID_273F&PID_1003` * `USB\VID_273F` + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +|`DfuFlags` | Optional quirks for a DFU device which doesn't follow the DFU 1.0 or 1.1 specification | 1.0.1| +|`DfuForceVersion` | Forces a specific DFU version for the hardware device. This is required if the device does not set, or sets incorrectly, items in the DFU functional descriptor. |1.0.1| +|`DfuJabraDetach` | Assigns the two magic bytes sent to the Jabra hardware when the device is in runtime mode to make it switch into DFU mode.|1.0.1| diff --git a/plugins/nvme/README.md b/plugins/nvme/README.md index ca6685d8c..da9cc9dd1 100644 --- a/plugins/nvme/README.md +++ b/plugins/nvme/README.md @@ -26,3 +26,11 @@ added: * `STORAGE-DELL-${component-id}` and any optional GUID saved in the vendor extension block. + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +| `NvmeBlockSize` | The block size used for NVMe writes | 1.1.3 | diff --git a/plugins/rts54hid/README.md b/plugins/rts54hid/README.md index 9ea488829..53798d7de 100644 --- a/plugins/rts54hid/README.md +++ b/plugins/rts54hid/README.md @@ -23,3 +23,12 @@ Child I²C devices are created using the device number as a suffix, for instance * `USB\VID_0BDA&PID_1100&I2C_01` +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +| `Rts54SlaveAddr` | The slave address of a child module. | 1.1.3 | +| `Rts54I2cSpeed` | The I2C speed to operate at (0, 1, 2). | 1.1.3 | +| `Rts54RegisterAddrLen` | The I2C register address length of commands | 1.1.3 | diff --git a/src/README.md b/src/README.md new file mode 100644 index 000000000..63423e78b --- /dev/null +++ b/src/README.md @@ -0,0 +1,137 @@ +Quirk use +--------- +Quirks are defined by creating an INI style file in the compiled in quirk location (typically `/usr/share/fwupd/quirks.d`). + +The quirk is declared by creating a group based upon the `DeviceInstanceId` or `GUID` +and then mapping out values to keys. + +## All plugins +All fwupd devices support the following quirks: + +### Plugin +Sets the plugin to use for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the plugin name, e.g. `csr` +* Minimum fwupd version: **1.1.0** +### UefiVersionFormat +Assigns the version format to use for a specific manufacturer. A specific version +format is sometimes chosen to match the appearance of other systems or +specifications. +* Key: a %FU_HWIDS_KEY_MANUFACTURER, e.g. `Alienware` +* Value: the version format, e.g. `none` +* Supported values: `none`, `use-triplet` +* Minimum fwupd version: **1.0.1** +### ComponentIDs +Assigns the version format to use for a specific AppStream component. A specific +version format is sometimes chosen to match the appearance of other systems or +specifications. +* Key: the optionally wildcarded AppStream ID e.g. `com.dell.uefi*.firmware` +* Value: the version format, e.g. `none` +* Minimum fwupd version: **1.0.1** +### Flags +Assigns optional quirks to use for a 8bitdo device +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the quirk, e.g. `is-bootloader` +* Supported values: + * `none`: no device quirks + * `is-bootloader`: device is in bootloader mode +* Minimum fwupd version: **1.0.3** +### Summary +Sets a summary for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* the device summary, e.g. `An open source display colorimeter` +* Minimum fwupd version: **1.0.2** +### Icon +Adds an icon name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the device icon name, e.g. `media-removable` +* Minimum fwupd version: **1.0.2** +### Name +Sets a name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the device name, e.g. `ColorHug` +* Minimum fwupd version: **1.0.2** +### Guid +Adds an extra GUID for a specific hardware device. If the value provided is not +already a suitable GUID, it will be converted to one. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.0.3** +### CounterpartGuid +Adds an counterpart GUID for a specific hardware device. If the value provided +is not already a suitable GUID, it will be converted to one. A counterpart +GUID is typically the GUID of the same device in bootloader or runtime mode, +if they have a different device PCI or USB ID. Adding this type of GUID does +not cause a "cascade" by matching using the quirk database. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.1.2** +### ParentGuid +Adds an extra GUID to mark as the parent device. If the value provided is not +already a suitable GUID, it will be converted to one. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.1.2** +### Children +Adds one or more virtual devices to a physical device. To set the object type +of the child device use a pipe before the object type, for instance: +`FuRts54xxDeviceUSB\VID_0763&PID_2806&I2C_01` If the type of device is not +specified the parent device type is used. If the values provided are not +already suitable GUIDs, they will be converted. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: The virtual device, delimited by a comma +* Minimum fwupd version: **1.1.2** +### Vendor +Sets a vendor name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the vendor, e.g. `Hughski Limited` +* Minimum fwupd version: **1.0.3** +### VendorId +Sets a vendor ID for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the vendor, e.g. `USB:0x123A` +* Minimum fwupd version: **1.1.2** +### Version +Sets a version for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: Version number, e.g. `1.2` +* Minimum fwupd version: **1.0.3** +### FirmwareSizeMin +Sets the minimum allowed firmware size. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in bytes, e.g. `512` +* Minimum fwupd version: **1.1.2** +### FirmwareSizeMax +Sets the maximum allowed firmware size. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in bytes, e.g. `1024` +* Minimum fwupd version: **1.1.2** +### InstallDuration +Sets the estimated time to flash the device +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in seconds, e.g. `60` +* Minimum fwupd version: **1.1.3** +### VersionFormat +Sets the version format the device should use for conversion. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: The quirk format, e.g. `quad` +* Minimum fwupd version: **1.2.0** + +## Plugin specific +Plugins may add support for additional quirks that are relevant only for +those plugins. View them by looking at the `README.md` in plugin directories. + +## Example +Here is an example as seen in the CSR plugin. + +``` +[DeviceInstanceId=USB\VID_0A12&PID_1337] +Plugin = csr +Name = H05 +Summary = Bluetooth Headphones +Icon = audio-headphones +Vendor = AIAIAI +[DeviceInstanceId=USB\VID_0A12&PID_1337&REV_2520] +Version = 1.2 +``` +Additional samples can be found in other plugins. diff --git a/src/fu-quirks.h b/src/fu-quirks.h index 02d4947fd..41a7f7a18 100644 --- a/src/fu-quirks.h +++ b/src/fu-quirks.h @@ -29,228 +29,23 @@ gboolean fu_quirks_get_kvs_for_guid (FuQuirks *self, const gchar *guid, GHashTableIter *iter); -/** - * FU_QUIRKS_PLUGIN: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the plugin name, e.g. `csr` - * - * Sets the plugin to use for a specific hardware device. - * - * Since: 1.1.0 - */ #define FU_QUIRKS_PLUGIN "Plugin" - -/** - * FU_QUIRKS_UEFI_VERSION_FORMAT: - * @key: a %FU_HWIDS_KEY_MANUFACTURER, e.g. `Alienware` - * @value: the version format, e.g. `none` - * - * Assigns the version format to use for a specific manufacturer. - * A specific version format is sometimes chosen to match the appearance of - * other systems or specifications. - * - * Default value: `use-triplet` - * - * Since: 1.0.1 - */ #define FU_QUIRKS_UEFI_VERSION_FORMAT "UefiVersionFormat" - -/** - * FU_QUIRKS_DAEMON_VERSION_FORMAT: - * @key: the optionally wildcarded AppStream ID e.g. `com.dell.uefi*.firmware` - * @value: the version format, e.g. `none` - * - * Assigns the version format to use for a specific AppStream component. - * A specific version format is sometimes chosen to match the appearance of - * other systems or specifications. - * - * Default value: `use-triplet` - * - * Since: 1.0.1 - */ #define FU_QUIRKS_DAEMON_VERSION_FORMAT "ComponentIDs" - -/** - * FU_QUIRKS_FLAGS: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the quirk, e.g. `is-bootloader` - * - * Assigns optional quirks to use for a 8Bitdo device. The list of supported - * quirks is thus: - * - * * `none`: No device quirks - * * `is-bootloader`: Device is in bootloader mode - * - * Since: 1.0.3 - */ #define FU_QUIRKS_FLAGS "Flags" - -/** - * FU_QUIRKS_SUMMARY: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the USB device summary, e.g. `An open source display colorimeter` - * - * Sets a name for a specific hardware device. - * - * Since: 1.0.2 - */ #define FU_QUIRKS_SUMMARY "Summary" - -/** - * FU_QUIRKS_ICON: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the USB device icon name, e.g. `media-removable` - * - * Adds an icon name for a specific hardware device. - * - * Since: 1.0.2 - */ #define FU_QUIRKS_ICON "Icon" - -/** - * FU_QUIRKS_NAME: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the USB device name, e.g. `ColorHug` - * - * Sets a name for a specific hardware device. - * - * Since: 1.0.2 - */ #define FU_QUIRKS_NAME "Name" - -/** - * FU_QUIRKS_GUID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` - * - * Adds an extra GUID for a specific hardware device. If the value provided is - * not already a suitable GUID, it will be converted to one. - * - * Since: 1.0.3 - */ #define FU_QUIRKS_GUID "Guid" - -/** - * FU_QUIRKS_COUNTERPART_GUID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` - * - * Adds an counterpart GUID for a specific hardware device. If the value - * provided is not already a suitable GUID, it will be converted to one. - * - * A counterpart GUID is typically the GUID of the same device in bootloader - * or runtime mode, if they have a different device PCI or USB ID. Adding this - * type of GUID does not cause a "cascade" by matching using the quirk database. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_COUNTERPART_GUID "CounterpartGuid" - -/** - * FU_QUIRKS_PARENT_GUID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` - * - * Adds an extra GUID to mark as the parent device. If the value provided is - * not already a suitable GUID, it will be converted to one. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_PARENT_GUID "ParentGuid" - -/** - * FU_QUIRKS_CHILDREN: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `USB\VID_0763&PID_2806&I2C_01` - * - * Adds one or more virtual devices to a physical device, delimited by comma. - * - * To set the object type of the child device use a pipe before the object type, - * for instance: `FuRts54xxDevice|USB\VID_0763&PID_2806&I2C_01` - * If the type of device is not specified the parent device type is used. - * - * If the values provided are not already suitable GUIDs, they will be - * converted. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_CHILDREN "Children" - -/** - * FU_QUIRKS_VERSION: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806&REV_0001` - * @value: the version number, e.g. `1.2` - * - * Sets a version for a specific hardware device. - * - * Since: 1.0.3 - */ #define FU_QUIRKS_VERSION "Version" - -/** - * FU_QUIRKS_VENDOR: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `Hughski Limited` - * - * Sets a vendor name for a specific hardware device. - * - * Since: 1.0.3 - */ #define FU_QUIRKS_VENDOR "Vendor" - -/** - * FU_QUIRKS_VENDOR_ID: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `USB:0x123A` - * - * Sets a vendor ID for a specific hardware device. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_VENDOR_ID "VendorId" - -/** - * FU_QUIRKS_FIRMWARE_SIZE_MIN: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `0x10000` - * - * Sets the minimum allowed firmware size. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_FIRMWARE_SIZE_MIN "FirmwareSizeMin" - -/** - * FU_QUIRKS_FIRMWARE_SIZE_MAX: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `0x10000` - * - * Sets the maximum allowed firmware size. - * - * Since: 1.1.2 - */ #define FU_QUIRKS_FIRMWARE_SIZE_MAX "FirmwareSizeMax" - -/** - * FU_QUIRKS_INSTALL_DURATION: - * @key: the USB device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` - * @value: the estimated time for flashing the device in seconds - * - * Sets the estimated time to flash the device - * - * Since: 1.1.3 - */ #define FU_QUIRKS_INSTALL_DURATION "InstallDuration" - -/** - * FU_QUIRKS_VERSION_FORMAT: - * @key: the device ID, e.g. `HwId=USB\VID_0763&PID_2806` - * @value: the quirk format, e.g. `quad` - * - * Sets the version format the device should use for conversion. - * - * Since: 1.2.0 - */ #define FU_QUIRKS_VERSION_FORMAT "VersionFormat" G_END_DECLS From 69fca1d754a94976836cdf881a4d0d7a5482ede8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 13 Nov 2018 15:09:41 +0000 Subject: [PATCH 076/254] Fix a use-after-free when using valgrind and --immediate-exit --- src/fu-debug.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/fu-debug.c b/src/fu-debug.c index 0384e2479..5497e469a 100644 --- a/src/fu-debug.c +++ b/src/fu-debug.c @@ -14,6 +14,7 @@ #include typedef struct { + GOptionGroup *group; gboolean verbose; gboolean console; gchar **plugin_verbose; @@ -23,6 +24,8 @@ typedef struct { static void fu_debug_free (FuDebug *self) { + g_option_group_set_parse_hooks (self->group, NULL, NULL); + g_option_group_unref (self->group); g_strfreev (self->plugin_verbose); g_strfreev (self->daemon_verbose); g_free (self); @@ -174,19 +177,19 @@ fu_debug_post_parse_hook (GOptionContext *context, return TRUE; } +/*(transfer): full */ GOptionGroup * fu_debug_get_option_group (void) { - GOptionGroup *group; FuDebug *self = g_new0 (FuDebug, 1); - group = g_option_group_new ("debug", - /* TRANSLATORS: for the --verbose arg */ - _("Debugging Options"), - /* TRANSLATORS: for the --verbose arg */ - _("Show debugging options"), - self, (GDestroyNotify) fu_debug_free); - g_option_group_set_parse_hooks (group, + self->group = g_option_group_new ("debug", + /* TRANSLATORS: for the --verbose arg */ + _("Debugging Options"), + /* TRANSLATORS: for the --verbose arg */ + _("Show debugging options"), + self, (GDestroyNotify) fu_debug_free); + g_option_group_set_parse_hooks (self->group, fu_debug_pre_parse_hook, fu_debug_post_parse_hook); - return group; + return g_option_group_ref (self->group); } From ac458d34365512e2b07d529cee7cab89e86e0083 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 13 Nov 2018 11:12:09 +0000 Subject: [PATCH 077/254] Guess the version format when it is not provided The most important change here is that versions without dots (not a 'semver') are treated as 'PLAIN' rather than 'UNKNOWN'. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 2 +- src/fu-common-version.c | 68 +++++++++++++++++++++++-- src/fu-common-version.h | 1 + src/fu-device.c | 24 +++++++++ src/fu-device.h | 3 +- src/fu-self-test.c | 21 +++++++- 6 files changed, 110 insertions(+), 9 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 461a68b67..00e8d6baf 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -332,7 +332,7 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, device_entry[i].version.version_8[2], device_entry[i].version.version_8[3]); g_debug ("\tParsed version %s", self->ec_version); - fu_device_set_version (self, self->ec_version); + fu_device_set_version (FU_DEVICE (self), self->ec_version); } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_MST) { self->raw_versions->mst_version = device_entry[i].version.version_32; diff --git a/src/fu-common-version.c b/src/fu-common-version.c index bc98c2784..fd8869a27 100644 --- a/src/fu-common-version.c +++ b/src/fu-common-version.c @@ -202,6 +202,17 @@ fu_common_vercmp_chunk (const gchar *str1, const gchar *str2) return fu_common_vercmp_char (str1[i], str2[i]); } +static gboolean +_g_ascii_is_digits (const gchar *str) +{ + g_return_val_if_fail (str != NULL, FALSE); + for (gsize i = 0; str[i] != '\0'; i++) { + if (!g_ascii_isdigit (str[i])) + return FALSE; + } + return TRUE; +} + /** * fu_common_version_parse: * @version: A version number @@ -228,7 +239,6 @@ fu_common_version_parse (const gchar *version) gchar *endptr = NULL; guint64 tmp; guint base; - guint i; /* already dotted decimal */ if (g_strstr_len (version, -1, ".") != NULL) @@ -245,10 +255,8 @@ fu_common_version_parse (const gchar *version) base = 16; } else { /* for non-numeric content, just return the string */ - for (i = 0; version[i] != '\0'; i++) { - if (!g_ascii_isdigit (version[i])) - return g_strdup (version); - } + if (!_g_ascii_is_digits (version)) + return g_strdup (version); base = 10; } @@ -261,6 +269,56 @@ fu_common_version_parse (const gchar *version) return fu_common_version_from_uint32 ((guint32) tmp, FU_VERSION_FORMAT_TRIPLET); } +/** + * fu_common_version_guess_format: + * @version: A version number, e.g. "1.2.3" + * + * Guesses the version format from the version number. This is only a heuristic + * and plugins and components should explicitly set the version format whenever + * possible. + * + * If the version format cannot be guessed with any degree of accuracy, the + * %FU_VERSION_FORMAT_UNKNOWN constant is returned. + * + * Returns: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_QUAD + * + * Since: 1.2.0 + */ +FuVersionFormat +fu_common_version_guess_format (const gchar *version) +{ + guint sz; + g_auto(GStrv) split = NULL; + + /* nothing to use */ + if (version == NULL || version[0] == '\0') + return FU_VERSION_FORMAT_UNKNOWN; + + /* no dots, assume just text */ + split = g_strsplit (version, ".", -1); + sz = g_strv_length (split); + if (sz == 1) + return FU_VERSION_FORMAT_PLAIN; + + /* check for only-digit semver version */ + for (guint i = 0; split[i] != NULL; i++) { + /* check sections are plain numbers */ + if (!_g_ascii_is_digits (split[i])) + return FU_VERSION_FORMAT_UNKNOWN; + } + + /* the most common formats */ + if (sz == 2) + return FU_VERSION_FORMAT_PAIR; + if (sz == 3) + return FU_VERSION_FORMAT_TRIPLET; + if (sz == 4) + return FU_VERSION_FORMAT_QUAD; + + /* unknown! */ + return FU_VERSION_FORMAT_UNKNOWN; +} + /** * fu_common_vercmp: * @version_a: the release version, e.g. 1.2.3 diff --git a/src/fu-common-version.h b/src/fu-common-version.h index 8bcbcd059..3538316b9 100644 --- a/src/fu-common-version.h +++ b/src/fu-common-version.h @@ -45,5 +45,6 @@ gchar *fu_common_version_from_uint32 (guint32 val, gchar *fu_common_version_from_uint16 (guint16 val, FuVersionFormat flags); gchar *fu_common_version_parse (const gchar *version); +FuVersionFormat fu_common_version_guess_format (const gchar *version); #endif /* __FU_COMMON_VERSION_H__ */ diff --git a/src/fu-device.c b/src/fu-device.c index e998fdf95..3fd374213 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -14,6 +14,7 @@ #include "fu-common.h" #include "fu-common-guid.h" +#include "fu-common-version.h" #include "fu-device-private.h" #include "fu-mutex.h" @@ -1046,6 +1047,29 @@ fu_device_set_id (FuDevice *self, const gchar *id) fwupd_device_set_id (FWUPD_DEVICE (self), id_hash); } +/** + * fu_device_set_version: + * @self: A #FuDevice + * @version: a string, e.g. `1.2.3` + * + * Sets the device version, autodetecting the version format if required. + * + * Since: 1.2.1 + **/ +void +fu_device_set_version (FuDevice *self, const gchar *version) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (version != NULL); + + /* try to autodetect the version-format */ + if (priv->version_format == FU_VERSION_FORMAT_UNKNOWN) + priv->version_format = fu_common_version_guess_format (version); + fwupd_device_set_version (FWUPD_DEVICE (self), version); +} + /** * fu_device_ensure_id: * @self: A #FuDevice diff --git a/src/fu-device.h b/src/fu-device.h index 1b80db894..9fe7b018e 100644 --- a/src/fu-device.h +++ b/src/fu-device.h @@ -94,7 +94,6 @@ FuDevice *fu_device_new (void); #define fu_device_set_update_state(d,v) fwupd_device_set_update_state(FWUPD_DEVICE(d),v) #define fu_device_set_vendor(d,v) fwupd_device_set_vendor(FWUPD_DEVICE(d),v) #define fu_device_set_vendor_id(d,v) fwupd_device_set_vendor_id(FWUPD_DEVICE(d),v) -#define fu_device_set_version(d,v) fwupd_device_set_version(FWUPD_DEVICE(d),v) #define fu_device_set_version_lowest(d,v) fwupd_device_set_version_lowest(FWUPD_DEVICE(d),v) #define fu_device_set_version_bootloader(d,v) fwupd_device_set_version_bootloader(FWUPD_DEVICE(d),v) #define fu_device_set_flashes_left(d,v) fwupd_device_set_flashes_left(FWUPD_DEVICE(d),v) @@ -158,6 +157,8 @@ void fu_device_set_metadata_integer (FuDevice *self, guint value); void fu_device_set_id (FuDevice *self, const gchar *id); +void fu_device_set_version (FuDevice *self, + const gchar *version); const gchar *fu_device_get_physical_id (FuDevice *self); void fu_device_set_physical_id (FuDevice *self, const gchar *physical_id); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index c6f6c2179..75b21eb57 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -52,6 +52,20 @@ fu_self_test_mkroot (void) g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); } +static void +fu_common_version_guess_format_func (void) +{ + g_assert_cmpint (fu_common_version_guess_format (NULL), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format (""), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1234ac"), ==, FU_VERSION_FORMAT_PLAIN); + g_assert_cmpint (fu_common_version_guess_format ("1.2"), ==, FU_VERSION_FORMAT_PAIR); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3"), ==, FU_VERSION_FORMAT_TRIPLET); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4"), ==, FU_VERSION_FORMAT_QUAD); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4.5"), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1a.2b.3"), ==, FU_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1"), ==, FU_VERSION_FORMAT_PLAIN); +} + static void fu_engine_requirements_missing_func (void) { @@ -857,7 +871,8 @@ fu_engine_history_func (void) " [Release]\n" " Version: 1.2.3\n" " Checksum: SHA1(%s)\n" - " TrustFlags: none\n", + " TrustFlags: none\n" + " VersionFormat: triplet\n", checksum); ret = fu_test_compare_lines (device_str, device_str_expected, &error); g_assert_no_error (error); @@ -986,7 +1001,8 @@ fu_engine_history_error_func (void) " [Release]\n" " Version: 1.2.3\n" " Checksum: SHA1(%s)\n" - " TrustFlags: none\n", + " TrustFlags: none\n" + " VersionFormat: triplet\n", checksum); ret = fu_test_compare_lines (device_str, device_str_expected, &error); g_assert_no_error (error); @@ -3214,6 +3230,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func); g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func); g_test_add_func ("/fwupd/common{guid}", fu_common_guid_func); g_test_add_func ("/fwupd/common{version}", fu_common_version_func); g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func); From 3ccce7151e0fa295e42333412074d4e64b49178c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 13 Nov 2018 15:46:57 +0000 Subject: [PATCH 078/254] trivial: Mark GParamSpec values as static to reduce RSS --- libfwupd/fwupd-client.c | 6 +++--- libfwupd/fwupd-remote.c | 4 ++-- src/fu-keyring-result.c | 8 ++++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index b079fe800..311b6f6b1 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1595,7 +1595,7 @@ fwupd_client_class_init (FwupdClientClass *klass) */ pspec = g_param_spec_uint ("status", NULL, NULL, 0, FWUPD_STATUS_LAST, FWUPD_STATUS_UNKNOWN, - G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_STATUS, pspec); /** @@ -1607,7 +1607,7 @@ fwupd_client_class_init (FwupdClientClass *klass) */ pspec = g_param_spec_uint ("percentage", NULL, NULL, 0, 100, 0, - G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_PERCENTAGE, pspec); /** @@ -1618,7 +1618,7 @@ fwupd_client_class_init (FwupdClientClass *klass) * Since: 0.9.6 */ pspec = g_param_spec_string ("daemon-version", NULL, NULL, - NULL, G_PARAM_READABLE); + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_DAEMON_VERSION, pspec); } diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index 99f62e8b8..1d40778af 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -1099,7 +1099,7 @@ fwupd_remote_class_init (FwupdRemoteClass *klass) * Since: 0.9.3 */ pspec = g_param_spec_string ("id", NULL, NULL, - NULL, G_PARAM_READWRITE); + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_ID, pspec); /** @@ -1110,7 +1110,7 @@ fwupd_remote_class_init (FwupdRemoteClass *klass) * Since: 0.9.3 */ pspec = g_param_spec_boolean ("enabled", NULL, NULL, - FALSE, G_PARAM_READWRITE); + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_ENABLED, pspec); } diff --git a/src/fu-keyring-result.c b/src/fu-keyring-result.c index 5deeb6adb..42f024387 100644 --- a/src/fu-keyring-result.c +++ b/src/fu-keyring-result.c @@ -98,11 +98,15 @@ fu_keyring_result_class_init (FuKeyringResultClass *klass) pspec = g_param_spec_int64 ("timestamp", NULL, NULL, 0, G_MAXINT64, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_TIMESTAMP, pspec); pspec = g_param_spec_string ("authority", NULL, NULL, NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_AUTHORITY, pspec); } From e9dfeb49c197b6070d48110c4025a6a06002c295 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Nov 2018 09:36:08 +0000 Subject: [PATCH 079/254] trivial: Remove unused functionality --- src/fu-plugin.c | 17 ----------------- src/fu-plugin.h | 1 - 2 files changed, 18 deletions(-) diff --git a/src/fu-plugin.c b/src/fu-plugin.c index b5af82f4c..e07a5fcdb 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -741,23 +741,6 @@ fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, cons return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key)); } -/** - * fu_plugin_get_supported: - * @self: A #FuPlugin - * - * Gets all the device GUIDs supported by the daemon. - * - * Returns: (element-type utf8) (transfer none): GUIDs - * - * Since: 1.0.0 - **/ -GPtrArray * -fu_plugin_get_supported (FuPlugin *self) -{ - FuPluginPrivate *priv = GET_PRIVATE (self); - return priv->supported_guids; -} - void fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios) { diff --git a/src/fu-plugin.h b/src/fu-plugin.h index 273777703..fc10c1166 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -91,7 +91,6 @@ gboolean fu_plugin_get_enabled (FuPlugin *self); void fu_plugin_set_enabled (FuPlugin *self, gboolean enabled); GUsbContext *fu_plugin_get_usb_context (FuPlugin *self); -GPtrArray *fu_plugin_get_supported (FuPlugin *self); void fu_plugin_device_add (FuPlugin *self, FuDevice *device); void fu_plugin_device_remove (FuPlugin *self, From aabdc371c165394e0547e8fb6381743f2c25fc54 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Nov 2018 10:11:08 +0000 Subject: [PATCH 080/254] Query the XbSilo when calling fu_plugin_check_supported() This means we don't have to have all the thousands of GUIDs as tiny allocated strings being passed around to all plugins in a GPtrArray. This also reduces our heap usage by about 6%. --- src/fu-engine.c | 50 +++++++++++++---------------------------- src/fu-plugin-private.h | 2 -- src/fu-plugin.c | 31 +++++++++---------------- src/fu-plugin.h | 4 +++- 4 files changed, 28 insertions(+), 59 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 61c18e57f..7409d2780 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -62,7 +62,6 @@ struct _FuEngine guint coldplug_delay; FuPluginList *plugin_list; GPtrArray *plugin_filter; - GPtrArray *supported_guids; GPtrArray *udev_subsystems; FuSmbios *smbios; FuHwids *hwids; @@ -1080,25 +1079,6 @@ fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, return TRUE; } -static gchar * -fu_engine_get_guids_from_store (XbSilo *silo) -{ - GString *str; - g_autoptr(GPtrArray) provides = NULL; - - /* return a string with all the firmware components in the silo */ - provides = xb_silo_query (silo, "components/component/provides/firmware[@type='flashed']", 0, NULL); - if (provides == NULL) - return NULL; - str = g_string_new (NULL); - for (guint i = 0; i < provides->len; i++) { - XbNode *prov = XB_NODE (g_ptr_array_index (provides, i)); - g_string_append_printf (str, "%s,", xb_node_get_text (prov)); - } - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); -} - static gchar * fu_engine_get_boot_time (void) { @@ -1801,7 +1781,6 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) { GPtrArray *remotes; g_autofree gchar *cachedirpkg = NULL; - g_autofree gchar *guids_str = NULL; g_autofree gchar *xmlbfn = NULL; g_autoptr(GFile) xmlb = NULL; g_autoptr(GPtrArray) devices = NULL; @@ -1881,17 +1860,6 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) if (components != NULL) g_debug ("%u components now in silo", components->len); - /* update the list of supported GUIDs */ - g_ptr_array_set_size (self->supported_guids, 0); - guids_str = fu_engine_get_guids_from_store (self->silo); - if (guids_str != NULL) { - g_auto(GStrv) guids = g_strsplit (guids_str, ",", -1); - for (guint i = 0; guids[i] != NULL; i++) { - g_ptr_array_add (self->supported_guids, - g_steal_pointer (&guids[i])); - } - } - /* did any devices SUPPORTED state change? */ devices = fu_device_list_get_all (self->device_list); for (guint i = 0; i < devices->len; i++) { @@ -3360,6 +3328,18 @@ fu_engine_add_plugin_filter (FuEngine *self, const gchar *plugin_glob) g_ptr_array_add (self->plugin_filter, g_strdup (plugin_glob)); } +static gboolean +fu_engine_plugin_check_supported_cb (FuPlugin *plugin, const gchar *guid, FuEngine *self) +{ + g_autoptr(XbNode) n = NULL; + g_autofree gchar *xpath = NULL; + xpath = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']", + guid); + n = xb_silo_query_first (self->silo, xpath, NULL); + return n != NULL; +} + gboolean fu_engine_load_plugins (FuEngine *self, GError **error) { @@ -3402,7 +3382,6 @@ fu_engine_load_plugins (FuEngine *self, GError **error) fu_plugin_set_usb_context (plugin, self->usb_ctx); fu_plugin_set_hwids (plugin, self->hwids); fu_plugin_set_smbios (plugin, self->smbios); - fu_plugin_set_supported (plugin, self->supported_guids); fu_plugin_set_udev_subsystems (plugin, self->udev_subsystems); fu_plugin_set_quirks (plugin, self->quirks); fu_plugin_set_runtime_versions (plugin, self->runtime_versions); @@ -3441,6 +3420,9 @@ fu_engine_load_plugins (FuEngine *self, GError **error) g_signal_connect (plugin, "set-coldplug-delay", G_CALLBACK (fu_engine_plugin_set_coldplug_delay_cb), self); + g_signal_connect (plugin, "check-supported", + G_CALLBACK (fu_engine_plugin_check_supported_cb), + self); /* add */ fu_plugin_list_add (self->plugin_list, plugin); @@ -3870,7 +3852,6 @@ fu_engine_init (FuEngine *self) self->history = fu_history_new (); self->plugin_list = fu_plugin_list_new (); self->plugin_filter = g_ptr_array_new_with_free_func (g_free); - self->supported_guids = g_ptr_array_new_with_free_func (g_free); self->udev_subsystems = g_ptr_array_new_with_free_func (g_free); self->runtime_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->compile_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); @@ -3918,7 +3899,6 @@ fu_engine_finalize (GObject *obj) g_object_unref (self->hwids); g_object_unref (self->history); g_object_unref (self->device_list); - g_ptr_array_unref (self->supported_guids); g_ptr_array_unref (self->plugin_filter); g_ptr_array_unref (self->udev_subsystems); g_hash_table_unref (self->runtime_versions); diff --git a/src/fu-plugin-private.h b/src/fu-plugin-private.h index 2ff7f9ab2..bb40c3ca4 100644 --- a/src/fu-plugin-private.h +++ b/src/fu-plugin-private.h @@ -20,8 +20,6 @@ void fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx); void fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids); -void fu_plugin_set_supported (FuPlugin *self, - GPtrArray *supported_guids); void fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems); void fu_plugin_set_quirks (FuPlugin *self, diff --git a/src/fu-plugin.c b/src/fu-plugin.c index e07a5fcdb..ca965f1d9 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -48,7 +48,6 @@ typedef struct { FuQuirks *quirks; GHashTable *runtime_versions; GHashTable *compile_versions; - GPtrArray *supported_guids; GPtrArray *udev_subsystems; FuSmbios *smbios; GHashTable *devices; /* platform_id:GObject */ @@ -63,6 +62,7 @@ enum { SIGNAL_DEVICE_REGISTER, SIGNAL_RECOLDPLUG, SIGNAL_SET_COLDPLUG_DELAY, + SIGNAL_CHECK_SUPPORTED, SIGNAL_LAST }; @@ -514,15 +514,9 @@ fu_plugin_get_hwids (FuPlugin *self) gboolean fu_plugin_check_supported (FuPlugin *self, const gchar *guid) { - FuPluginPrivate *priv = GET_PRIVATE (self); - if (priv->supported_guids == NULL) - return FALSE; - for (guint i = 0; i < priv->supported_guids->len; i++) { - const gchar *guid_tmp = g_ptr_array_index (priv->supported_guids, i); - if (g_strcmp0 (guid, guid_tmp) == 0) - return TRUE; - } - return FALSE; + gboolean retval = FALSE; + g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval); + return retval; } /** @@ -596,15 +590,6 @@ fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids) g_set_object (&priv->hwids, hwids); } -void -fu_plugin_set_supported (FuPlugin *self, GPtrArray *supported_guids) -{ - FuPluginPrivate *priv = GET_PRIVATE (self); - if (priv->supported_guids != NULL) - g_ptr_array_unref (priv->supported_guids); - priv->supported_guids = g_ptr_array_ref (supported_guids); -} - void fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems) { @@ -1750,6 +1735,12 @@ fu_plugin_class_init (FuPluginClass *klass) G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); + signals[SIGNAL_CHECK_SUPPORTED] = + g_signal_new ("check-supported", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, check_supported), + NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 1, G_TYPE_STRING); } static void @@ -1790,8 +1781,6 @@ fu_plugin_finalize (GObject *object) g_object_unref (priv->hwids); if (priv->quirks != NULL) g_object_unref (priv->quirks); - if (priv->supported_guids != NULL) - g_ptr_array_unref (priv->supported_guids); if (priv->udev_subsystems != NULL) g_ptr_array_unref (priv->udev_subsystems); if (priv->smbios != NULL) diff --git a/src/fu-plugin.h b/src/fu-plugin.h index fc10c1166..2764c65bd 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -43,8 +43,10 @@ struct _FuPluginClass guint duration); void (* device_register) (FuPlugin *self, FuDevice *device); + gboolean (* check_supported) (FuPlugin *self, + const gchar *guid); /*< private >*/ - gpointer padding[24]; + gpointer padding[23]; }; /** From af2d1c285ebce4a4fd7af60d683870bd314f4dfc Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Nov 2018 10:53:06 +0000 Subject: [PATCH 081/254] trivial: Do not show all the HWIDs at daemon startup The same information can be seen in `/usr/libexec/fwupd/fwupdtool hwids` and for most users verbose mode is turned off -- so we're doing all those expensive allocations for nothing. --- src/fu-hwids.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/fu-hwids.c b/src/fu-hwids.c index b72af2c5e..61777ae30 100644 --- a/src/fu-hwids.c +++ b/src/fu-hwids.c @@ -394,7 +394,6 @@ fu_hwids_setup (FuHwids *self, FuSmbios *smbios, GError **error) for (guint i = 0; i < 15; i++) { g_autofree gchar *guid = NULL; g_autofree gchar *key = NULL; - g_autofree gchar *values = NULL; g_autoptr(GError) error_local = NULL; /* get the GUID and add to hash */ @@ -407,11 +406,7 @@ fu_hwids_setup (FuHwids *self, FuSmbios *smbios, GError **error) g_hash_table_insert (self->hash_guid, g_strdup (guid), GUINT_TO_POINTER (1)); - g_ptr_array_add (self->array_guids, g_strdup (guid)); - - /* show what makes up the GUID */ - values = fu_hwids_get_replace_values (self, key, NULL); - g_debug ("{%s} <- %s", guid, values); + g_ptr_array_add (self->array_guids, g_steal_pointer (&guid)); } return TRUE; From 840184929b55aa79c2e599a333599b3ac78f8aee Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Nov 2018 12:00:15 +0000 Subject: [PATCH 082/254] trivial: Fix some function prefixes for Thunderbolt --- plugins/thunderbolt/fu-plugin-thunderbolt.c | 11 ++++------- plugins/thunderbolt/fu-self-test.c | 12 ++++++------ plugins/thunderbolt/fu-thunderbolt-image.c | 12 ++++++------ plugins/thunderbolt/fu-thunderbolt-image.h | 4 ++-- plugins/thunderbolt/fu-thunderbolt-tool.c | 2 +- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index 24936a423..19e577dbf 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -207,9 +207,9 @@ fu_plugin_thunderbolt_is_native (GUdevDevice *udevice, gboolean *is_native, GErr controller_fw = g_bytes_new_take (content, length); - return fu_plugin_thunderbolt_controller_is_native (controller_fw, - is_native, - error); + return fu_thunderbolt_image_controller_is_native (controller_fw, + is_native, + error); } static void @@ -436,10 +436,7 @@ fu_plugin_thunderbolt_validate_firmware (GUdevDevice *udevice, return VALIDATION_FAILED; controller_fw = g_bytes_new_take (content, length); - - return fu_plugin_thunderbolt_validate_image (controller_fw, - blob_fw, - error); + return fu_thunderbolt_image_validate (controller_fw, blob_fw, error); } static gboolean diff --git a/plugins/thunderbolt/fu-self-test.c b/plugins/thunderbolt/fu-self-test.c index 37f492ff8..5cdf5a296 100644 --- a/plugins/thunderbolt/fu-self-test.c +++ b/plugins/thunderbolt/fu-self-test.c @@ -1045,40 +1045,40 @@ test_image_validation (ThunderboltTest *tt, gconstpointer user_data) g_assert_nonnull (bad_data); /* now for some testing ... this should work */ - val = fu_plugin_thunderbolt_validate_image (ctl_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, fwi_data, &error); g_assert_no_error (error); g_assert_cmpint (val, ==, VALIDATION_PASSED); /* these all should fail */ /* valid controller, bad update data */ - val = fu_plugin_thunderbolt_validate_image (ctl_data, ctl_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, ctl_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [ctl, ctl]: %s", error->message); g_clear_error (&error); - val = fu_plugin_thunderbolt_validate_image (ctl_data, bad_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, bad_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [ctl, bad]: %s", error->message); g_clear_error (&error); /* bad controller data, valid update data */ - val = fu_plugin_thunderbolt_validate_image (fwi_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (fwi_data, fwi_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [fwi, fwi]: %s", error->message); g_clear_error (&error); - val = fu_plugin_thunderbolt_validate_image (bad_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (bad_data, fwi_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [bad, fwi]: %s", error->message); g_clear_error (&error); /* both bad */ - val = fu_plugin_thunderbolt_validate_image (bad_data, bad_data, &error); + val = fu_thunderbolt_image_validate (bad_data, bad_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [bad, bad]: %s", error->message); diff --git a/plugins/thunderbolt/fu-thunderbolt-image.c b/plugins/thunderbolt/fu-thunderbolt-image.c index 231248141..40a5951ec 100644 --- a/plugins/thunderbolt/fu-thunderbolt-image.c +++ b/plugins/thunderbolt/fu-thunderbolt-image.c @@ -642,9 +642,9 @@ compare_pd_existence (guint16 id, } FuPluginValidation -fu_plugin_thunderbolt_validate_image (GBytes *controller_fw, - GBytes *blob_fw, - GError **error) +fu_thunderbolt_image_validate (GBytes *controller_fw, + GBytes *blob_fw, + GError **error) { gboolean is_host; guint16 device_id; @@ -779,9 +779,9 @@ fu_plugin_thunderbolt_validate_image (GBytes *controller_fw, } gboolean -fu_plugin_thunderbolt_controller_is_native (GBytes *controller_fw, - gboolean *is_native, - GError **error) +fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, + gboolean *is_native, + GError **error) { guint32 controller_sections[SECTION_COUNT] = { [DIGITAL_SECTION] = 0 }; gsize fw_size; diff --git a/plugins/thunderbolt/fu-thunderbolt-image.h b/plugins/thunderbolt/fu-thunderbolt-image.h index f094f563a..f00c42e19 100644 --- a/plugins/thunderbolt/fu-thunderbolt-image.h +++ b/plugins/thunderbolt/fu-thunderbolt-image.h @@ -15,11 +15,11 @@ typedef enum { UNKNOWN_DEVICE, } FuPluginValidation; -FuPluginValidation fu_plugin_thunderbolt_validate_image (GBytes *controller_fw, +FuPluginValidation fu_thunderbolt_image_validate (GBytes *controller_fw, GBytes *blob_fw, GError **error); -gboolean fu_plugin_thunderbolt_controller_is_native (GBytes *controller_fw, +gboolean fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, gboolean *is_native, GError **error); diff --git a/plugins/thunderbolt/fu-thunderbolt-tool.c b/plugins/thunderbolt/fu-thunderbolt-tool.c index 79466c938..a4675aab6 100644 --- a/plugins/thunderbolt/fu-thunderbolt-tool.c +++ b/plugins/thunderbolt/fu-thunderbolt-tool.c @@ -82,7 +82,7 @@ main (int argc, char **argv) controller = g_bytes_new_take (controller_data, controller_len); } - validation = fu_plugin_thunderbolt_validate_image (controller, image, &error); + validation = fu_thunderbolt_image_validate (controller, image, &error); g_assert_no_error (error); g_assert_cmpint (validation, ==, VALIDATION_PASSED); From 86b79fb03915315c0fba6670989ea072be2e8a5e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 14 Nov 2018 12:20:23 +0000 Subject: [PATCH 083/254] Speed up fwupd startup by loading less thunderbolt firmware We load the Thunderbolt controller firmware to see if the controller is in native mode, as this changes the GUID. If the controller is asleep the firmware is not cached by the kernel and it can take more than 4 seconds to read out 504kB of firmware. We only need the first two 64-byte chunks, so only read what is required. This speeds up fwupd starting substantially, and also means we don't have to allocate a giant chunk of heap memory just to inspect one byte. Fixes: https://github.com/hughsie/fwupd/issues/848 --- plugins/thunderbolt/fu-plugin-thunderbolt.c | 16 +++++++++++----- plugins/thunderbolt/fu-thunderbolt-image.c | 8 +++++--- plugins/thunderbolt/fu-thunderbolt-image.h | 4 ++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index 19e577dbf..d04e1ea68 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -193,19 +193,25 @@ fu_plugin_thunderbolt_udev_get_version (GUdevDevice *udevice) static gboolean fu_plugin_thunderbolt_is_native (GUdevDevice *udevice, gboolean *is_native, GError **error) { + gsize nr_chunks; g_autoptr(GFile) nvmem = NULL; g_autoptr(GBytes) controller_fw = NULL; - gchar *content; - gsize length; + g_autoptr(GInputStream) istr = NULL; nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, TRUE, error); if (nvmem == NULL) return FALSE; - if (!g_file_load_contents (nvmem, NULL, &content, &length, NULL, error)) + /* read just enough bytes to read the status byte */ + nr_chunks = (FU_TBT_OFFSET_NATIVE + FU_TBT_CHUNK_SZ - 1) / FU_TBT_CHUNK_SZ; + istr = G_INPUT_STREAM (g_file_read (nvmem, NULL, error)); + if (istr == NULL) + return FALSE; + controller_fw = g_input_stream_read_bytes (istr, + nr_chunks * FU_TBT_CHUNK_SZ, + NULL, error); + if (controller_fw == NULL) return FALSE; - - controller_fw = g_bytes_new_take (content, length); return fu_thunderbolt_image_controller_is_native (controller_fw, is_native, diff --git a/plugins/thunderbolt/fu-thunderbolt-image.c b/plugins/thunderbolt/fu-thunderbolt-image.c index 40a5951ec..c88aed9b0 100644 --- a/plugins/thunderbolt/fu-thunderbolt-image.c +++ b/plugins/thunderbolt/fu-thunderbolt-image.c @@ -787,8 +787,10 @@ fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, gsize fw_size; const guint8 *fw_data = g_bytes_get_data (controller_fw, &fw_size); const FuThunderboltFwObject controller = { fw_data, fw_size, controller_sections }; - - const FuThunderboltFwLocation location = { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }; - + const FuThunderboltFwLocation location = { + .offset = FU_TBT_OFFSET_NATIVE, + .len = 1, + .description = "Native", + .mask = 0x20 }; return read_bool (&location, &controller, is_native, error); } diff --git a/plugins/thunderbolt/fu-thunderbolt-image.h b/plugins/thunderbolt/fu-thunderbolt-image.h index f00c42e19..ee7d000ce 100644 --- a/plugins/thunderbolt/fu-thunderbolt-image.h +++ b/plugins/thunderbolt/fu-thunderbolt-image.h @@ -15,6 +15,10 @@ typedef enum { UNKNOWN_DEVICE, } FuPluginValidation; +/* byte offsets in firmware image */ +#define FU_TBT_OFFSET_NATIVE 0x7B +#define FU_TBT_CHUNK_SZ 0x40 + FuPluginValidation fu_thunderbolt_image_validate (GBytes *controller_fw, GBytes *blob_fw, GError **error); From 5ed4d968acaac49c92029bbe2867d6cd904e277b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Nov 2018 14:34:50 +0000 Subject: [PATCH 084/254] trivial: Add InstallDuration values for ColorHug devices --- plugins/colorhug/colorhug.quirk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/colorhug/colorhug.quirk b/plugins/colorhug/colorhug.quirk index da33620d1..81f25f4bc 100644 --- a/plugins/colorhug/colorhug.quirk +++ b/plugins/colorhug/colorhug.quirk @@ -6,6 +6,7 @@ Guid = 40338ceb-b966-4eae-adae-9c32edfcc484 FirmwareSizeMin = 0x2000 FirmwareSizeMax = 0x8000 CounterpartGuid = USB\VID_273F&PID_1001 +InstallDuration = 8 [DeviceInstanceId=USB\VID_273F&PID_1001] Plugin = colorhug @@ -14,6 +15,7 @@ Summary = An open source display colorimeter Icon = colorimeter-colorhug Guid = 40338ceb-b966-4eae-adae-9c32edfcc484 CounterpartGuid = USB\VID_273F&PID_1000 +InstallDuration = 8 # ColorHug2 [DeviceInstanceId=USB\VID_273F&PID_1004] @@ -25,12 +27,14 @@ Guid = 2082b5e0-7a64-478a-b1b2-e3404fab6dad FirmwareSizeMin = 0x2000 FirmwareSizeMax = 0x8000 CounterpartGuid = USB\VID_273F&PID_1005 +InstallDuration = 8 [DeviceInstanceId=USB\VID_273F&PID_1005] Plugin = colorhug Flags = is-bootloader Guid = 2082b5e0-7a64-478a-b1b2-e3404fab6dad CounterpartGuid = USB\VID_273F&PID_1004 +InstallDuration = 8 # ColorHugALS [DeviceInstanceId=USB\VID_273F&PID_1007] @@ -41,9 +45,11 @@ Guid = 84f40464-9272-4ef7-9399-cd95f12da696 FirmwareSizeMin = 0x1000 FirmwareSizeMax = 0x4000 CounterpartGuid = USB\VID_273F&PID_1006 +InstallDuration = 5 [DeviceInstanceId=USB\VID_273F&PID_1006] Plugin = colorhug Flags = halfsize,is-bootloader Guid = 84f40464-9272-4ef7-9399-cd95f12da696 CounterpartGuid = USB\VID_273F&PID_1007 +InstallDuration = 5 From 0443a4170adac9e0edf1967948b3a6c954685254 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Nov 2018 14:35:04 +0000 Subject: [PATCH 085/254] trivial: Add InstallDuration values for Unifying devices --- plugins/unifying/unifying.quirk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/unifying/unifying.quirk b/plugins/unifying/unifying.quirk index b135c990c..2191bb080 100644 --- a/plugins/unifying/unifying.quirk +++ b/plugins/unifying/unifying.quirk @@ -3,6 +3,7 @@ Plugin = unifying Flags = is-receiver VendorId=USB:0x046D +InstallDuration = 7 # Nordic [DeviceInstanceId=USB\VID_046D&PID_AAAA] @@ -10,6 +11,7 @@ Plugin = unifying Flags = is-bootloader,is-nordic FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 # Nordic Pico [DeviceInstanceId=USB\VID_046D&PID_AAAE] @@ -17,6 +19,7 @@ Plugin = unifying Flags = is-bootloader,is-nordic FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 # Texas [DeviceInstanceId=USB\VID_046D&PID_AAAC] @@ -24,6 +27,7 @@ Plugin = unifying Flags = is-bootloader,is-texas FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 # Texas Pico [DeviceInstanceId=USB\VID_046D&PID_AAAD] @@ -31,3 +35,4 @@ Plugin = unifying Flags = is-bootloader,is-texas FirmwareSizeMin = 0x4000 CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 From 9cf352db2fed1c6d7989ab49553e5386bfdedc76 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Nov 2018 15:04:04 +0000 Subject: [PATCH 086/254] trivial: Add InstallDuration values for 8bitdo devices --- plugins/ebitdo/ebitdo.quirk | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/ebitdo/ebitdo.quirk b/plugins/ebitdo/ebitdo.quirk index bf39badf4..b46c001f8 100644 --- a/plugins/ebitdo/ebitdo.quirk +++ b/plugins/ebitdo/ebitdo.quirk @@ -5,6 +5,7 @@ Flags = is-bootloader [DeviceInstanceId=USB\VID_2DC8&PID_5750] Plugin = ebitdo Flags = is-bootloader +InstallDuration = 120 # FC30 [DeviceInstanceId=USB\VID_1235&PID_AB11] @@ -13,6 +14,7 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_AB11] Plugin = ebitdo Flags = none +InstallDuration = 120 # NES30 [DeviceInstanceId=USB\VID_1235&PID_AB12] @@ -21,6 +23,7 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_AB12] Plugin = ebitdo Flags = none +InstallDuration = 120 # SFC30 [DeviceInstanceId=USB\VID_1235&PID_AB21] @@ -29,6 +32,7 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_AB21] Plugin = ebitdo Flags = none +InstallDuration = 120 # SNES30 [DeviceInstanceId=USB\VID_1235&PID_AB20] @@ -37,6 +41,7 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_AB20] Plugin = ebitdo Flags = none +InstallDuration = 120 # FC30PRO [DeviceInstanceId=USB\VID_1002&PID_9000] @@ -45,6 +50,7 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_9000] Plugin = ebitdo Flags = none +InstallDuration = 120 # NES30PRO [DeviceInstanceId=USB\VID_2002&PID_9000] @@ -53,6 +59,7 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_9001] Plugin = ebitdo Flags = none +InstallDuration = 120 # FC30_ARCADE [DeviceInstanceId=USB\VID_8000&PID_1002] @@ -61,6 +68,7 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_1002] Plugin = ebitdo Flags = none +InstallDuration = 120 # SF30 PRO/SN30 PRO ## Dinput mode (Start + B) @@ -70,3 +78,4 @@ Flags = none [DeviceInstanceId=USB\VID_2DC8&PID_6001] Plugin = ebitdo Flags = none +InstallDuration = 120 From ab1bc89ea851a568869b127befa6d5f8a97981ae Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Nov 2018 15:04:35 +0000 Subject: [PATCH 087/254] trivial: Do a single query when getting a component by a set of GUIDs --- src/fu-engine.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 7409d2780..a1500f38f 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -633,18 +633,18 @@ static XbNode * fu_engine_store_get_app_by_guids (XbSilo *silo, FuDevice *device) { GPtrArray *guids = fu_device_get_guids (device); + g_autoptr(GString) xpath = g_string_new (NULL); + g_autoptr(XbNode) component = NULL; for (guint i = 0; i < guids->len; i++) { - g_autoptr(XbNode) component = NULL; - g_autofree gchar *xpath = NULL; const gchar *guid = g_ptr_array_index (guids, i); - xpath = g_strdup_printf ("components/component/" - "provides/firmware[@type='flashed'][text()='%s']/" - "../..", - guid); - component = xb_silo_query_first (silo, xpath, NULL); - if (component != NULL) - return g_steal_pointer (&component); + xb_string_append_union (xpath, + "components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../..", guid); } + component = xb_silo_query_first (silo, xpath->str, NULL); + if (component != NULL) + return g_steal_pointer (&component); return NULL; } From d76ed3de28870e76dca3333edce07e1b5868d5f4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Nov 2018 15:05:36 +0000 Subject: [PATCH 088/254] Fix flashing the 8bitdo SF30 We have to check for the SUPPORTED flag _after_ the FuDeviceList has added the missing GUIDs from the device when it was in runtime mode. --- src/fu-engine.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index a1500f38f..179989842 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3080,13 +3080,13 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)) fu_engine_plugin_device_register (self, device); + /* create new device */ + fu_device_list_add (self->device_list, device); + /* match the metadata at this point so clients can tell if the * device is worthy */ if (fu_engine_is_device_supported (self, device)) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED); - - /* create new device */ - fu_device_list_add (self->device_list, device); } static void From 8a2eaa5514c654c2c1891fd59e7407d9d8e53fa4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Nov 2018 17:07:52 +0000 Subject: [PATCH 089/254] trivial: Move the release descriptions to the metainfo.xml file This matches what a lot of other projects do, and means we can easily format the release notes back into NEWS format, but also into HTML and Markdown. This also means we can show the correct update description in gnome-software when building a flatpak, rather than falling back to the generic project description. --- NEWS | 890 -------------------- RELEASE | 6 +- contrib/debian/docs | 2 +- contrib/fwupd.spec.in | 2 +- data/org.freedesktop.fwupd.metainfo.xml | 1026 +++++++++++++++++++++++ 5 files changed, 1032 insertions(+), 894 deletions(-) delete mode 100644 NEWS diff --git a/NEWS b/NEWS deleted file mode 100644 index 4e73c4758..000000000 --- a/NEWS +++ /dev/null @@ -1,890 +0,0 @@ -Version 1.2.0 -~~~~~~~~~~~~~ -Released: 2018-11-07 - -New Features: - - Add a plugin for an upcoming Dell USB-C dock (Mario Limonciello) - - Add a standalone installer creation script (Mario Limonciello) - - Add support for devices to show an estimated flash time (Mario Limonciello) - - Add support for some new Realtek USB devices (Richard Hughes) - - Allow firmware files to depend on versions from other devices (Richard Hughes) - - Allow setting the version format from a quirk entry (Richard Hughes) - - Port from libappstream-glib to libxmlb for a large reduction in RSS (Richard Hughes) - - Stop any running daemon over dbus when using fu-tool (Mario Limonciello) - - Support the Intel ME version format (Richard Hughes) - -Bugfixes: - - Add version format quirks for several Lenovo machines (Richard Hughes) - - Adjust panamera ESM update routine for some reported issues (Mario Limonciello) - - Adjust synapticsmst EVB board handling (Mario Limonciello, RyanChang) - - Check the amount of free space on the ESP (Richard Hughes) - - Don't show devices pending a reboot in GetUpgrades (Mario Limonciello) - - Ensure that parent ID is created before creating quirked children (Mario Limonciello) - - Optionally wait for replug before updating a device (Mario Limonciello) - - Set the full AMT device version including the BuildNum (Richard Hughes) - - Sort the firmware sack by component priority (Richard Hughes) - - Stop showing errors when no Dell dock plugged in (Mario Limonciello) - - Stop showing the current release during updates in fwupdmgr (Mario Limonciello) - - Update all sub-devices for a composite update (Mario Limonciello) - - Use HTTPS_PROXY if set (Richard Hughes) - -Version 1.1.2 -~~~~~~~~~~~~~ -Released: 2018-09-10 - -New Features: - - Add a new device flag "ignore-validation" that will override checks (Mario Limonciello) - - Add a new plugin to enumerate EC firmware (Richard Hughes) - - Add a new plugin to update NVMe hardware (Richard Hughes, Mario Limonciello) - - Add a plugin for updating using the flashrom command line tool (Richard Hughes) - - Allow the device list to take care of waiting for the device replug (Richard Hughes) - - Allow updating just one specific device from the command line (Richard Hughes) - - Allow upgrades using a self-signed fwupd.efi binary (Richard Hughes) - - Download firmware if the user specifies a URI (Richard Hughes) - - Include serial number in daemon device output when trusted (Mario Limonciello) - - Notify all plugins of device removals through a new vfunc (Mario Limonciello) - - Use boltd force power API if available (Mario Limonciello) - -Bugfixes: - - Add an install hook for classic snap (Mario Limonciello) - - Allow forcing installation even if no AC power is applied (Mario Limonciello) - - Allow using --force to ignore version_lowest (Mario Limonciello) - - Always use the same HardwareIDs as Windows (Richard Hughes) - - Check the device state before assuming a fake DFU runtime (Richard Hughes) - - Copy over parent GUIDs from other plugin donors (Mario Limonciello) - - Detect location of python3 interpreter (Mario Limonciello) - - Do not add udev devices after a small delay (Richard Hughes) - - Don't fail to run if compiled without GPG/PKCS7 (Salud Lemus, Mario Limonciello) - - Fix a segfault in fwupdtool caused by cleanup of USB plugins (Mario Limonciello) - - Implement the systemd recommendations for offline updates (Richard Hughes) - - Improve performance when reading keys from the quirk database (Richard Hughes) - - Remove children of devices when the parent is removed (Mario Limonciello) - - Rewrite synapticsmst to use modern error handling (Mario Limonciello) - - Rewrite the unifying plugin to use the new daemon-provided functionality (Richard Hughes) - - Show a time estimate on the progressbar after an update has started (Mario Limonciello) - -Version 1.1.1 -~~~~~~~~~~~~~ -Released: 2018-08-13 - -New Features: - - Add support for the Synaptics Panamera hardware (Mario Limonciello) - - Add validation for Alpine and Titan Ridge (Andrei Emeltchenko, Mika Westerberg) - - Improve the Redfish plugin to actually work with real hardware (Gary Lin) - -Bugfixes: - - Allow different plugins to add the same device (Richard Hughes) - - Allow flashing unifying devices in recovery mode (Richard Hughes) - - Allow running synapticsmst on non-Dell hardware (Mario Limonciello) - - Check the ESP for sanity at at startup (Richard Hughes, Mario Limonciello) - - Do not hold hidraw devices open forever (Richard Hughes) - - Don't override _FORTIFY_SOURCE when building the EFI binary (Richard Hughes) - - Don't show passwords in fwupdmgr (Richard Hughes, Mario Limonciello) - - Fix a potential segfault in smbios data parsing (Mario Limonciello) - - Fix encoding the GUID into the capsule EFI variable (Mario Limonciello) - - Fix various bugs when reading the thunderbolt version number (Mika Westerberg) - - Reboot synapticsmst devices at the end of flash cycle (Mario Limonciello) - - Show status messages when the daemon is initializing (Mario Limonciello) - - Show the correct title when updating devices (Richard Hughes, Mario Limonciello) - - Show the reasons that plugins are not run on the CLI (Mario Limonciello) - - Use localedir in po/make-images (Jan Tojnar) - -Version 1.1.0 -~~~~~~~~~~~~~ -Released: 2018-07-11 - -New Features: - - Add a initial Redfish support (Richard Hughes) - - Add a tool to mimic the original fwupdate CLI interface (Richard Hughes) - - Allow devices to assign a plugin from the quirk subsystem (Richard Hughes) - - Change the quirk file structure to be more efficient (Richard Hughes) - - Merge fwupdate functionality into fwupd (Richard Hughes, Mario Limonciello) - - Run a plugin vfunc before and after all the composite devices are updated (Richard Hughes) - - Support more Wacom tablets (Richard Hughes) - -Bugfixes: - - Add release information for locked devices (Richard Hughes) - - Allow building with older meson (Mario Limonciello) - - Detect the EFI system partition location at runtime (Mario Limonciello) - - Do not use 8bitdo bootloader commands after a successful flash (Richard Hughes) - - Enable accesing downloaded files in flatpak and snap (Mario Limonciello) - - Fix a potential buffer overflow when applying a DFU patch (Richard Hughes) - - Fix downgrading older releases to devices (Richard Hughes) - - Fix flashing devices that require a manual replug (Richard Hughes) - - Fix several small memory leaks in various places (Richard Hughes) - - Fix the retrieval of Redfish version (Gary Lin) - - Fix unifying failure to detach when using a slow host controller (Richard Hughes) - - Set the Wacom device status when erasing and writing firmware (Richard Hughes) - - Show errors in the CLI if unable to access directory (Mario Limonciello) - - Use the parent device name for Wacom sub-modules (Richard Hughes) - -Version 1.0.8 -~~~~~~~~~~~~~ -Released: 2018-06-07 - -New Features: - - Add an plugin to update some future Wacom tablets (Richard Hughes) - - Add 'fwupdmgr get-topology' to show logical device tree (Richard Hughes, Mario Limonciello) - - Add support for creating a flatpak (Richard Hughes) - - Add support for creating a snap (Mario Limonciello, Richard Hughes) - - Add support for Motorola S-record files (Richard Hughes) - - Add the Linux Foundation public GPG keys for firmware and metadata (Richard Hughes) - - Show a translated warning when the server is limiting downloads (Richard Hughes) - -Bugfixes: - - Add a firmware diagnostic tool called fwupdtool (Richard Hughes, Mario Limonciello) - - Adjust all licensing to LGPL 2.1+ (Mario Limonciello) - - Allow installing more than one firmware using 'fwupdmgr install' (Richard Hughes) - - Allow specifying hwids with OR relationships (Richard Hughes) - - Do not call fu_plugin_init() on blacklisted plugins (Richard Hughes) - - Do not require libcolorhug to build (Richard Hughes) - - Fix a crash in libfwupd where no device ID is set (Richard Hughes) - - Fix a potential DoS in libdfu by limiting holes to 1MiB (Richard Hughes) - - Fix a segfault that sometimes occurs during cleanup of USB plugins (Mario Limonciello) - - Fix Hardware-ID{0,1,2,12} compatibility with Microsoft (Gergely Risko) - - Hide devices that aren't updatable by default in fwupdmgr (Mario Limonciello) - - Search all UEFI GUIDs when matching hardware (Richard Hughes, Mario Limonciello) - - Stop matching Nintendo Switch Pro in the 8bitdo plugin (Mario Limonciello) - -Version 1.0.7 -~~~~~~~~~~~~~ -Released: 2018-04-30 - -New Features: - - Add enable-remote and disable-remote commands to fwupdmgr (Richard Hughes) - - Add fu_plugin_add_compile_version() for libraries to use (Richard Hughes) - - Allow requiring specific versions of libraries for firmware updates (Richard Hughes) - - If no remotes are enabled try to enable the LVFS (Mario Limonciello) - - Show a warning with interactive prompt when enabling a remote (Richard Hughes) - -Bugfixes: - - Check that EFI system partition is mounted before update (Mario Limonciello) - - Disable synapticsmst remote control on failure (Sjoerd Simons) - - Don't recoldplug thunderbolt to fix a flashing failure (Mario Limonciello) - - Fix SQL error when running 'fwupdmgr clear-offline' (Richard Hughes) - - Improve the update report message (Mario Limonciello) - - Only enumerate Dell Docks if the type is known (Sjoerd Simons) - - Only run certtool if a new enough gnutls is present (Mario Limonciello) - - Prevent a client crash if the daemon somehow sends invalid data (Richard Hughes) - - Reboot after scheduling using logind not systemd (Richard Hughes) - - Use the right encoding for the label in make-images (Niels Ole Salscheider) - -Version 1.0.6 -~~~~~~~~~~~~~ -Released: 2018-03-12 - -New Features: - - Add bash completion for fwupdmgr (Mario Limonciello) - - Add support for newest Thunderbolt chips (Andrei Emeltchenko) - - Allow all functions that take device arguments to be prompted (Mario Limonciello) - - Allow devices to use the runtime version when in bootloader mode (Richard Hughes) - - Allow overriding ESP mount point via conf file (Mario Limonciello) - - Delete any old fwupdate capsules and efivars when launching fwupd (Richard Hughes) - - Generate Vala bindings (Robert Ancell) - -Bugfixes: - - Allow ctrl-d out of the prompt for devices (Mario Limonciello) - - Allow to create package out of provided binary (Andrei Emeltchenko) - - Correct handling of unknown Thunderbolt devices (Yehezkel Bernat) - - Correctly detect new remotes that are manually copied (Richard Hughes) - - Fix a crash related to when passing device to downgrade in CLI (Mario Limonciello) - - Fix running the self tests when no fwupd is installed (Richard Hughes) - - Fix Unifying signature writing and parsing for Texas bootloader (Ogier Bouvier) - - Only send success and failure reports to the server (Richard Hughes) - - Use a CNAME to redirect to the correct CDN for metadata (Richard Hughes) - - Use a longer timeout when powering back the Thunderbolt device (Richard Hughes) - -Version 1.0.5 -~~~~~~~~~~~~~ -Released: 2018-02-14 - -New Features: - - Offer to reboot when processing an offline update (Richard Hughes) - - Report the efivar, libsmbios and fwupdate library versions (Mario Limonciello) - - Report Thunderbolt safe mode and SecureBoot status (Mario Limonciello) - - Show the user a URL when they report a known problem (Richard Hughes) - - Support split cabinet archives as produced by Windows Update (Richard Hughes) - -Bugfixes: - - Be more careful deleting and modifying device history (Richard Hughes) - - Clarify which devices don't have upgrades (Mario Limonciello) - - Ensure the Thunderbolt version is xx.yy (Richard Hughes) - - Fix a daemon warning when using fwupdmgr get-results (Richard Hughes) - - Fix crasher with MST flashing (Mario Limonciello) - - Fix DFU detach with newer releases of libusb (Richard Hughes) - - Include the device VID and PID when generating the device-id (Richard Hughes) - - Set the RemoteId when using GetDetails (Richard Hughes) - - Stop matching 8bitdo DS4 controller VID/PID (Mario Limonciello) - - Use help2man for dfu-tool and drop docbook dependencies (Mario Limonciello) - - Use ngettext for any strings with plurals (Piotr Drąg) - - Use the default value if ArchiveSizeMax is unspecified (Richard Hughes) - -Version 1.0.4 -~~~~~~~~~~~~~ -Released: 2018-01-25 - -New Features: - - Add D-Bus methods to get and modify the history information (Richard Hughes) - - Allow the user to share firmware update success or failure (Richard Hughes) - - Ask the user to refresh metadata when it is very old (Richard Hughes) - - Store firmware update success and failure to a local database (Richard Hughes) - -Bugfixes: - - Add a device name for locked UEFI devices (Mario Limonciello) - - Allow each plugin to opt-in to the recoldplug action (Richard Hughes) - - Fix firmware downloading using gnome-software (Richard Hughes) - - Fix UX capsule reference to the one specified in efivar (Mario Limonciello) - - Never add two devices to the daemon with the same ID (Richard Hughes) - - Rescan supported flags when refreshing metadata (Richard Hughes) - -Version 1.0.3 -~~~~~~~~~~~~~ -Released: 2018-01-09 - -New Features: - - Add a new plugin to add support for CSR "Driverless DFU" (Richard Hughes) - - Add initial SF30/SN30 Pro support (Mario Limonciello) - - Support AppStream metadata with relative URLs (Richard Hughes) - -Bugfixes: - - Add more metadata to the user-agent string (Richard Hughes) - - Block owned Dell TPM updates (Mario Limonciello) - - Choose the correct component from provides matches using requirements (Richard Hughes) - - Do not try to parse huge compressed archive files (Richard Hughes) - - Fix a double-free bug in the Udev code (Philip Withnall) - - Handle Thunderbolt "native" mode (Yehezkel Bernat) - - Use the new functionality in libgcab >= 1.0 to avoid writing temp files (Richard Hughes) - -Version 1.0.2 -~~~~~~~~~~~~~ -Released: 2017-11-28 - -New Features: - - Add a plugin for the Nitrokey Storage device (Richard Hughes) - - Add support for the original AVR DFU protocol (Richard Hughes) - - Allow different plugins to claim the same device (Richard Hughes) - - Allow quirks to set common USB properties (Richard Hughes) - - Move a common plugin functionality out to a new shared object (Richard Hughes) - - Optionally delay the device removal for better replugging (Richard Hughes) - - Set environment variables to allow easy per-plugin debugging (Richard Hughes) - - Use a SHA1 hash for the internal DeviceID (Richard Hughes) - -Bugfixes: - - Add quirk for AT32UC3B1256 as used in the RubberDucky (Richard Hughes) - - Disable the dell plugin if libsmbios fails (Mario Limonciello) - - Don't register for USB UDev events to later ignore them (Richard Hughes) - - Fix a possible buffer overflow when debugging ebitdo devices (Richard Hughes) - - Fix critical warning when more than one remote fails to load (Richard Hughes) - - Fix DFU attaching AVR32 devices like the XMEGA (Richard Hughes) - - Ignore useless Thunderbolt device types (Mario Limonciello) - - Refactor ColorHug into a much more modern plugin (Richard Hughes) - - Release the Steelseries interface if getting the version failed (Richard Hughes) - - Remove autoconf-isms from the meson configure options (Richard Hughes) - - Show a nicer error message if the requirement fails (Richard Hughes) - - Sort the output of GetUpgrades correctly (Richard Hughes) - -Version 1.0.1 -~~~~~~~~~~~~~ -Released: 2017-11-09 - -New Features: - - Add support for HWID requirements (Richard Hughes) - - Add support for programming various AVR32 and XMEGA parts using DFU (Richard Hughes) - - Add the various DFU quirks for the Jabra Speak devices (Richard Hughes) - - Allow specifying the output file type for 'dfu-tool read' (Richard Hughes) - - Move the database of supported devices out into runtime loaded files (Richard Hughes) - - Support the IHEX record type 0x05 (Richard Hughes) - - Use help2man to generate the man page at build time (Richard Hughes) - - Use the new quirk infrastructure for version numbers (Richard Hughes) - -Bugfixes: - - Catch invalid Dell dock component requests (Mario Limonciello) - - Correctly output Intel HEX files with > 16bit offset addresses (Richard Hughes) - - Do not try to verify the element write if upload is unsupported (Richard Hughes) - - Fix a double-unref when updating any 8Bitdo device (Richard Hughes) - - Fix crash when enumerating with Dell dock connected but with no UEFI (Mario Limonciello) - - Fix uploading large firmware files over DFU (Richard Hughes) - - Format the BCD USB revision numbers correctly (Richard Hughes) - - Guess the DFU transfer size if it is not specified (Richard Hughes) - - Include the reset timeout as wValue to fix some DFU bootloaders (Richard Hughes) - - Make the error message clearer when sans fonts are missing (Mario Limonciello) - - Support devices with truncated DFU interface data (Richard Hughes) - - Use the correct remote-specified username and passord when using fwupdmgr (Richard Hughes) - - Use the correct wDetachTimeOut when writing DFU firmware (Richard Hughes) - - Verify devices with legacy VIDs are actually 8Bitdo controllers (Richard Hughes) - -Version 1.0.0 -~~~~~~~~~~~~~ -Released: 2017-10-09 - -Notes: - - This release breaks API and ABI to remove deprecated symbols - - libdfu is now not installed as a shared library - -New Features: - - Add a human-readable title for each remote (Richard Hughes) - - Add a method to return a list of upgrades for a specific device (Richard Hughes) - - Add an 'Summary' and 'Icons' properties to each device (Richard Hughes) - - Add FuDeviceLocker to simplify device open/close lifecycles (Richard Hughes) - - Add functionality to blacklist Dell HW with problems (Mario Limonciello) - - Add fu_plugin_check_supported() (Richard Hughes) - - Add fwupd_remote_get_checksum() to use in client programs (Richard Hughes) - - Add ModifyRemote as an easy way to enable and disable remotes (Richard Hughes) - - Add the plugin documentation to the main gtk-doc (Richard Hughes) - - Allow plugins to depend on each other (Richard Hughes) - - Disable the fallback USB plugin (Richard Hughes) - - Parse the SMBIOS v2 and v3 DMI tables directly (Richard Hughes) - - Support uploading the UEFI firmware splash image (Richard Hughes) - - Use the intel-wmi-thunderbolt kernel module to force power (Mario Limonciello) - -Bugfixes: - - Only run SMI to toggle host MST GPIO on Dell systems with host MST (Mario Limonciello) - - Disable unifying support if no CONFIG_HIDRAW support (Richard Hughes) - - Do not auto-open all USB devices at startup (Richard Hughes) - - Do not fail to load the daemon if cached metadata is invalid (Richard Hughes) - - Do not use system-specific infomation for UEFI PCI devices (Richard Hughes) - - Fix a crash when using fu_plugin_device_add_delay() (Richard Hughes) - - Fix the libdfu self test failure on s390 and ppc64 (Richard Hughes) - - Fix various printing issues with the progressbar (Richard Hughes) - - Generate the LD script from the GObject introspection data (Richard Hughes) - - Never fallback to an offline update from client code (Richard Hughes) - - Only set the Dell coldplug delay when we know we need it (Mario Limonciello) - - Prefer to use HWIDs to get DMI keys and DE table (Mario Limonciello) - -Version 0.9.7 -~~~~~~~~~~~~~ -Released: 2017-09-01 - -New Features: - - Add a configure switch for the LVFS remotes (Richard Hughes) - - Add a FirmwareBaseURI parameter to the remote config (Richard Hughes) - - Add a firmware builder that uses bubblewrap (Richard Hughes) - - Add a python script to create fwupd compatible cab files from Microsoft .exe files (Max Ehrlich) - - Add a thunderbolt plugin for new kernel interface (Christian Kellner, Yehezkel Bernat) - - Allow plugins to get DMI data from the hardware in a safe way (Richard Hughes) - - Allow plugins to set metadata on devices created by other plugins (Richard Hughes, Mario Limonciello) - - Optionally install the LVFS PKCS7 root certificate (Richard Hughes) - - Optionally use GnuTLS to verify PKCS7 certificates (Richard Hughes) - -Bugfixes: - - Add back options for HAVE_SYNAPTICS and HAVE_THUNDERBOLT (Mario Limonciello) - - Allow configuring systemd and udev directories (Mario Limonciello) - - Enable C99 support in meson.build (Philip Withnall) - - Fix an incomplete cipher when using XTEA on data not in 4 byte chunks (Richard Hughes) - - Fix minor const-correctness issues (Philip Withnall) - - Implement thunderbolt image validation (Yehezkel Bernat, Christian Kellner) - - Remove the confusing ALLOW_OFFLINE and ALLOW_ONLINE flags (Richard Hughes) - - Show a bouncing progress bar if the percentage remains at zero (Richard Hughes) - - Use a hwid to match supported systems for synapticsmst (Mario Limonciello) - - Use the new bootloader PIDs for Unifying pico receivers (Richard Hughes) - - When thunderbolt is in safe mode on a Dell recover using SMBIOS (Mario Limonciello) - -Version 0.9.6 -~~~~~~~~~~~~~ -Released: 2017-08-03 - -New Features: - - Add DfuPatch to support forward-only firmware patching (Richard Hughes) - - Add --version option to fwupdmgr (Richard Hughes, Mario Limonciello) - - Display all errors recorded by efi_error tracing (Mario Limonciello) - - Make building introspection optional (Patrick Ohly) - - Support embedded devices with local firmware metadata (Richard Hughes) - -Bugfixes: - - Check all the device GUIDs against the blacklist when added (Richard Hughes) - - Correct a memory leak in Dell plugin (Mario Limonciello, Richard Hughes) - - Default to "en" for UEFI capsule graphics (Mario Limonciello) - - Don't log a warning when an unknown unifying report is parsed (Richard Hughes) - - Enable test suite via /etc/fwupd.conf (Mario Limonciello) - - Fix a hang on 32 bit computers (Richard Hughes) - - Fix compilation of the policy on a variety of configurations (Mario Limonciello) - - Fix UEFI crash when the product name is NULL (Richard Hughes) - - Make flashing ebitdo devices work with fu-ebitdo-tool (Chris Lee) - - Make messages from installing capsules useful (Mario Limonciello) - - Make sure the unifying percentage completion goes from 0% to 100% (Richard Hughes) - - Run the plugin coldplug methods in a predictable order (Richard Hughes) - - Test UEFI for kernel support during coldplug (Mario Limonciello) - - Use new GUsb functionality to fix flashing Unifying devices (Richard Hughes) - -Version 0.9.5 -~~~~~~~~~~~~~ -Released: 2017-07-04 - -New Features: - - Add a get-remotes command to fwupdmgr (Richard Hughes) - - Add a plugin to get the version of the AMT ME interface (Richard Hughes) - - Add Arch Linux to CI (Bruno Pagani) - - Add some installed tests flashing actual hardware (Richard Hughes) - - Allow flashing Unifying devices in bootloader modes (Richard Hughes) - - Allow ordering the metadata remotes (Richard Hughes) - -Bugfixes: - - Do not check the runtime if the DFU device is in bootloader mode (Richard Hughes) - - Do not unlock devices when doing VerifyUpdate (Richard Hughes) - - Filter by Unifying SwId when making HID++2.0 requests (Richard Hughes) - - Fix downgrades when version_lowest is set (Richard Hughes) - - Fix the self tests when running on PPC64 big endian (Richard Hughes) - - Move the remotes parsing from the client to the server (Richard Hughes) - - Split up the Unifying HID++2.0 and HID++1.0 functionality (Richard Hughes) - - Store the metadata files rather than merging to one store (Richard Hughes) - - Use a longer timeout for some Unifying operations (Richard Hughes) - - Use the UFY DeviceID prefix for Unifying devides (Richard Hughes) - -Version 0.9.4 -~~~~~~~~~~~~~ -Released: 2017-06-15 - -New Features: - - Add installed tests that use the daemon (Richard Hughes) - - Add the ability to restrict firmware to specific vendors (Richard Hughes) - - Enable Travis CI for Fedora and Debian (Richard Hughes, Mario Limonciello) - - Export some more API for dealing with checksums (Richard Hughes) - - Generate a images for status messages during system firmware update (Peter Jones) - - Show progress download when refreshing metadata (Richard Hughes) - -Bugfixes: - - Compile with newer versions of meson (Richard Hughes, Mario Limonciello) - - Ensure that firmware provides are legal GUIDs (Richard Hughes) - - Fix a common crash when refreshing metadata (Richard Hughes) - - Use the correct type signature in the D-Bus introspection file (Richard Hughes) - -Version 0.9.3 -~~~~~~~~~~~~~ -Released: 2017-06-07 - -New Features: - - Add a 'downgrade' command to fwupdmgr (Richard Hughes) - - Add a 'get-releases' command to fwupdmgr (Richard Hughes) - - Add support for ConsoleKit2 (Eric Koegel) - - Add support for Microsoft HardwareIDs (Richard Hughes) - - Allow downloading metadata from more than just the LVFS (Richard Hughes) - - Allow multiple checksums on devices and releases (Richard Hughes) - -Bugfixes: - - Allow to specify bindir (Timo Gurr) - - Correctly open Unifying devices with original factory firmware (Richard Hughes) - - Deprecate some of the old FwupdResult API (Richard Hughes) - - Do not copy the origin from the new metadata file (Richard Hughes) - - Do not expect a Unifying reply when issuing a REBOOT command (Richard Hughes) - - Do not re-download firmware that exists in the cache (Richard Hughes) - - Fix a problem when testing for a Dell system (Mario Limonciello) - - Fix flashing new firmware to 8bitdo controllers (Richard Hughes) - - Increase minimum required AppStream-Glib version to 0.6.13 (Chris Mayo) - - Make documentation and man pages optional (Chris Mayo) - - Make systemd dependency at least version 231 (Mario Limonciello) - - Only decompress the firmware after the signature check (Richard Hughes) - - Remove 'lib' prefix when looking for libraries (Mirco Tischler) - - Return the remote ID when getting updates about hardware (Richard Hughes) - - Send the daemon the remote ID when sending firmware metadata (Richard Hughes) - -Version 0.9.2 -~~~~~~~~~~~~~ -Released: 2017-05-22 - -New Features: - - Add support for Unifying DFU features (Richard Hughes) - -Bugfixes: - - Do not spew a critial warning when parsing an invalid URI (Richard Hughes) - - Ensure device is closed if did not complete setup (Richard Hughes) - - Ensure steelseries device is closed if it returns an invalid packet (Richard Hughes) - - Fix man page installation location (Mario Limonciello) - - Ignore spaces in the Unifying version prefix (Richard Hughes) - - Set HAVE_POLKIT_0_114 when polkit is newer than 0.114 (Moritz Kiefer) - -Version 0.9.1 -~~~~~~~~~~~~~ -Released: 2017-04-28 - -New Features: - - Add a config option to allow runtime disabling plugins by name (Richard Hughes) - - Add the Meson build system and remove autotools (Richard Hughes) - - Support signed Intel HEX files (Richard Hughes) - -Bugfixes: - - Add DFU quirk for OpenPICC and SIMtrace (Richard Hughes) - - Create directories in /var/cache as required (Richard Hughes) - - Refactor the unifying plugin now we know more about the hardware (Richard Hughes) - - Set the source origin when saving metadata (Richard Hughes) - - Support proxy servers in fwupdmgr (Richard Hughes) - - Use a 60 second timeout on all client downloads (Richard Hughes) - -Version 0.8.1 -~~~~~~~~~~~~~ -Released: 2017-02-27 - -Bugfixes: - - Adjust systemd confinement restrictions (Mario Limonciello, Richard Hughes) - - Do not hardcode docbook2man path (Kai Krakow) - - Don't initialize libsmbios on unsupported systems (Mario Limonciello) - - Fix a crash when enumerating devices on a Dell WLD15 (Richard Hughes) - - Fix compiler warnings (Kai Krakow) - - Fix fwupdmgr timeout with missing pending database (Richard Hughes) - -Version 0.8.0 -~~~~~~~~~~~~~ -Released: 2017-02-08 - -New Features: - - Add a set of vfuncs that are run before and after a device update (Richard Hughes) - - Add Dell-specific functionality to allow other plugins turn on TBT/GPIO (Mario Limonciello) - - Add support for Intel Thunderbolt devices (Richard Hughes, Mario Limonciello) - - Add support for Logitech Unifying devices (Richard Hughes) - - Add support for Synaptics MST cascades hubs (Mario Limonciello) - - Add support for the Altus-Metrum ChaosKey device (Richard Hughes) - - Add VerifyUpdate to update the device checksums server-side (Richard Hughes) - - Allow the metadata to match a version of fwupd and the existing fw version (Richard Hughes) - -Bugfixes: - - Add a new method for forcing a controller to flash mode (Mario Limonciello) - - Always make sure we're getting a C99 compiler (Richard Hughes) - - Close USB devices before error returns (Tsunghan Liu) - - Don't read data from some DfuSe targets (Richard Hughes) - - Include all debug messages when run with --verbose (Richard Hughes) - - Return the pending UEFI update when not on AC power (Richard Hughes) - - Use a heuristic for the start address if the firmware has no DfuSe footer (Richard Hughes) - - Use more restrictive settings when running under systemd (Richard Hughes, Mario Limonciello) - -Version 0.7.5 -~~~~~~~~~~~~~ -Released: 2016-10-19 - -New Features: - - Add a 'replace-data' command to dfu-tool (Richard Hughes) - - Use an animated progress bar when performing DFU operations (Richard Hughes) - -Bugfixes: - - Add quirks for HydraBus as it does not have a DFU runtime (Richard Hughes) - - Don't create the UEFI dummy device if the unlock will happen on next boot (Richard Hughes) - - Enable hardening flags on more binaries (Mario Limonciello) - - Fix an assert when unlocking the dummy ESRT device (Richard Hughes) - - Fix writing firmware to devices using the ST reference bootloader (Richard Hughes) - - Match the Dell TB16 device (Mario Limonciello) - - Re-get the quirks when the DfuDevice gets a new GUsbDevice (Richard Hughes) - - Show the nicely formatted target name for DfuSe devices (Richard Hughes) - - Verify devices support updating in mode they are called (Mario Limonciello) - -Version 0.7.4 -~~~~~~~~~~~~~ -Released: 2016-09-19 - -New Features: - - Add dfu_firmware_add_symbol() (Richard Hughes) - - Allow the argument to 'dfu-tool set-release' be major.minor (Richard Hughes) - - Load the Altos USB descriptor from ELF files (Richard Hughes) - - Support writing the IHEX symbol table (Richard Hughes) - -Bugfixes: - - Add a fallback for older appstream-glib releases (Richard Hughes) - - Fix a possible crash when uploading firmware files using libdfu (Richard Hughes) - - Fix libfwupd self tests when a host-provided fwupd is not available (Richard Hughes) - - Show the human-readable version in the 'dfu-tool dump' output (Richard Hughes) - - Write the ELF files with the correct section type (Richard Hughes) - -Version 0.7.3 -~~~~~~~~~~~~~ -Released: 2016-08-29 - -New Features: - - Add a set-address and set-target-size commands to dfu-util (Richard Hughes) - - Add a small library for talking with 0bitdo hardware (Richard Hughes) - - Add Dell TPM and TB15/WD15 support via new Dell provider (Mario Limonciello) - - Add FU_DEVICE_FLAG_NEEDS_BOOTLOADER (Richard Hughes) - - Add fwupd_client_get_status() (Richard Hughes) - - Add fwupd_result_get_unique_id() (Richard Hughes) - - Add initial ELF reading and writing support to libdfu (Richard Hughes) - - Add support for installing multiple devices from a CAB file (Richard Hughes) - - Allow providers to export percentage completion (Richard Hughes) - - Show a progress notification when installing firmware (Richard Hughes) - - Show the vendor flashing instructions when installing (Richard Hughes) - -Bugfixes: - - Add XPS 9250 to Dell TPM modeswitch blacklist (Mario Limonciello) - - Allow blacklisting devices by their GUID (Richard Hughes) - - Conditionally enable all providers based upon installed (Mario Limonciello) - - Display flashes left in results output when it gets low (Mario Limonciello) - - Do not attempt to add DFU devices not in runtime mode (Richard Hughes) - - Do not use the deprecated GNOME_COMPILE_WARNINGS (Richard Hughes) - - Don't fail while checking versions or locked state (Richard Hughes) - - Embed fwupd version in generated documentation (Mario Limonciello) - - Ensure the ID is set when getting local firmware details (Richard Hughes) - - Fix gtk-doc build when srcdir != builddir (Ting-Wei Lan) - - Fix libdfu hang when parsing corrupt IHEX files (Richard Hughes) - - Ignore devices that do not add at least one GUID (Richard Hughes) - - In get-details output, display the blob filename (Mario Limonciello) - - Save the unique ID in the pending database (Richard Hughes) - - Support the 'DEVO' cipher kind in libdfu (Richard Hughes) - - Switch to the Amazon S3 CDN for firmware metadata (Richard Hughes) - - Update fwupdmgr manpage for new commands and arguments (Mario Limonciello) - - Use a private gnupg key store (Richard Hughes) - - Use the correct firmware when installing a composite device (Richard Hughes) - - Use the SHA1 hash of the local file data as the origin (Richard Hughes) - -Version 0.7.2 -~~~~~~~~~~~~~ -Released: 2016-06-13 - -New Features: - - Add a GetDetailsLocal() method to eventually replace GetDetails() (Richard Hughes) - - Add fu_device_get_alternate() (Richard Hughes) - - Allow devices to have multiple assigned GUIDs (Richard Hughes) - - Allow metainfo files to match only specific revisions of devices (Richard Hughes) - - Show the DFU protocol version in 'dfu-tool list' (Richard Hughes) - -Bugfixes: - - Enforce allowing providers to take away flash abilities (Mario Limonciello) - - Only claim the DFU interface when required (Richard Hughes) - - Only return updatable devices from GetDevices() (Richard Hughes) - -Version 0.7.1 -~~~~~~~~~~~~~ -Released: 2016-05-13 - -New Features: - - Add a --force flag to override provider warnings (Mario Limonciello) - - Add device-added, device-removed and device-changed signals (Richard Hughes) - - Add dfu_image_get_element_default() (Richard Hughes) - - Add for a new device field "Flashes Left" (Mario Limonciello) - - Add fwupd_client_connect() (Richard Hughes) - - Add the 'monitor' debugging command for fwupdmgr (Richard Hughes) - - Add the 'supported' flag to the FuDevice (Richard Hughes) - -Bugfixes: - - Add summary and name field for Rival SteelSeries (Mario Limonciello) - - Fix a critical warning when restarting the daemon (Richard Hughes) - - Fix BE issues when reading and writing DFU files (Mario Limonciello, Richard Hughes) - - Make the device display name nicer (Richard Hughes, Richard Hughes) - - Match the AppStream metadata after a device has been added (Richard Hughes) - - Remove non-interactive pinentry setting from fu-keyring (Mario Limonciello) - - Return all update descriptions newer than the installed version (Richard Hughes) - - Set the device description when parsing local firmware files (Richard Hughes) - -Version 0.7.0 -~~~~~~~~~~~~~ -Released: 2016-04-01 - -New Features: - - Add a version plugin for SteelSeries hardware (Richard Hughes) - - Add FwupdClient and FwupdResult to libfwupd (Richard Hughes) - - Generate gtk-doc documentation for libfwupd (Richard Hughes) - - Return the device flags when getting firmware details (Richard Hughes) - - Support other checksum kinds (Richard Hughes) - -Bugfixes: - - Add Alienware to the version quirk table (Mario Limonciello) - - Allow the test suite to run in %check (Richard Hughes) - - Do not return updates that require AC when on battery (Richard Hughes) - - Do not use /tmp for downloaded files (Richard Hughes) - - Test that GPG key import actually was successful (Mario Limonciello) - -Version 0.6.3 -~~~~~~~~~~~~~ -Released: 2016-03-14 - -New Features: - - Add an unlock method for devices (Richard Hughes) - - Add a simple plugin infrastructure (Richard Hughes) - - Add ESRT enable method into UEFI provider (Mario Limonciello) - - Install the hardcoded firmware AppStream file (Richard Hughes) - -Bugfixes: - - Correct the BCD version number for DFU 1.1 (Richard Hughes) - - Do not use deprecated API from libappstream-glib (Richard Hughes) - - Ignore the DFU runtime on the DW1820A (Richard Hughes) - - Only read PCI OptionROM firmware when devices are manually unlocked (Richard Hughes) - - Require AC power before scheduling some types of firmware update (Richard Hughes) - - Show ignored DFU devices in dfu-util, but not in fwupd (Richard Hughes) - -Version 0.6.2 -~~~~~~~~~~~~~ -Released: 2016-02-12 - -New Features: - - Add 'Created' and 'Modified' properties on managed devices (Richard Hughes) - -Bugfixes: - - Fix get-results for UEFI provider (Mario Limonciello) - - Support vendor-specific UEFI version encodings (Richard Hughes) - -Version 0.6.1 -~~~~~~~~~~~~~ -Released: 2016-01-19 - -Bugfixes: - - Always persist ColorHug devices after replug (Richard Hughes) - - Do not misdetect different ColorHug devices (Richard Hughes) - - Only dump the profiling data when run with --verbose (Richard Hughes) - -Version 0.6.0 -~~~~~~~~~~~~~ -Released: 2015-12-07 - -Notes: - - This release adds a new GObject library called libdfu and a command line - client called dfu-tool. This is a low-level tool used to upgrade USB device - firmware and can either be shipped in the same package as fwupd or split off - as separate subpackages. - -New Features: - - Add support for automatically updating USB DFU-capable devices (Richard Hughes) - -Bugfixes: - - Emit the changed signal after doing an update (Richard Hughes) - - Export the AppStream ID when returning device results (Richard Hughes) - - Fix compile with --disable-shared (Richard Hughes) - - Use new API available in fwup 0.5 (Richard Hughes, Mario Limonciello) - - Use the same device identification string format as Microsoft (Richard Hughes) - -Version 0.5.3 -~~~~~~~~~~~~~ -Released: 2015-11-05 - -Bugfixes: - - Avoid seeking when reading the file magic during refresh (Richard Hughes) - - Do not assume that the compressed XML data will be NUL terminated (Richard Hughes) - - Use the correct user agent string for fwupdmgr (Richard Hughes) - -Version 0.5.2 -~~~~~~~~~~~~~ -Released: 2015-10-28 - -New Features: - - Add profiling data to debug slow startup times (Richard Hughes) - - Support cabinet archives files with more than one firmware (Richard Hughes) - -Bugfixes: - - Add the update description to the GetDetails results (Richard Hughes) - - Clear the in-memory firmware store only after parsing a valid XML file (Richard Hughes) - - Ensure D-Bus remote errors are registered at fwupdmgr startup (Richard Hughes) - - Fix verify-update to produce components with the correct provide values (Richard Hughes) - - Require appstream-glib 0.5.1 (Mirco Tischler) - - Show the dotted-decimal representation of the UEFI version number (Richard Hughes) - - When the version is from the 'FW' extension do not cache the device (Richard Hughes) - -Version 0.5.1 -~~~~~~~~~~~~~ -Released: 2015-09-21 - -Bugfixes: - - Fix the error message when no devices can be updated (Richard Hughes) - - Fix reading symlink to prevent crash with some compilers (Kalev Lember) - -Version 0.5.0 -~~~~~~~~~~~~~ -Released: 2015-09-15 - -New Features: - - Raise the dep on GLib to support and use g_autoptr() (Richard Hughes) - -Bugfixes: - - Do not merge existing firmware metadata (Richard Hughes) - - Do not reboot if racing with the PackageKit offline update mechanism (Richard Hughes) - -Version 0.1.6 -~~~~~~~~~~~~~ -Released: 2015-09-10 - -New Features: - - Remove fwsignd, we have the LVFS now (Richard Hughes) - -Bugfixes: - - Add application metadata when getting the updates list (Richard Hughes) - - Depend on appstream-glib >= 0.5.0 (Richard Hughes) - - Don't apply firmware if something else is processing the update (Richard Hughes) - - Install fwupd into /usr/lib/$(triplet)/fwupd instead (Mario Limonciello) - - Simplify the version properties on devices to avoid complexity (Richard Hughes) - - Update the offline update service to invoke right command (Kalev Lember) - - Use the new secure metadata URI (Richard Hughes) - -Version 0.1.5 -~~~~~~~~~~~~~ -Released: 2015-08-12 - -Notes: - - For the device verification code to work correctly you need at least - libappstream-glib 0.5.0 installed. - -New Features: - - Add a Raspberry Pi firmware provider (Richard Hughes) - - Add a simple config file to store the correct LVFS download URI (Richard Hughes) - - Make parsing the option ROM runtime optional (Richard Hughes) - -Bugfixes: - - Allow fwupd to be autostarted by systemd (Richard Hughes) - - Allow no arguments to 'fwupdmgr verify-update' and use sane defaults (Richard Hughes) - - Devices with option ROM are always internal (Richard Hughes) - - Do not pre-convert the update description from AppStream XML (Richard Hughes) - - Fix validation of written firmware (Richard Hughes) - - Move the verification and metadata matching phase to the daemon (Richard Hughes) - - Sign the test binary with the correct key (Richard Hughes) - - Use the AppStream 0.9 firmware specification by default (Richard Hughes) - -Version 0.1.4 -~~~~~~~~~~~~~ -Released: 2015-07-25 - -Notes: - - In this release we've moved the LVFS website to the fwupd project and made - them work really well together. To update all the firmware on your system - is now just a case of "fwupdmgr refresh && fwupdmgr update" - - We've also added verification of BIOS and PCI ROM firmware, which may be - useful for forensics or to verify that system updates have been applied. - -New Features: - - Actually parse the complete PCI option ROM (Richard Hughes) - - Add a 'fwupdmgr update' command to update all devices to latest versions (Richard Hughes) - - Add a simple signing server that operates on .cab files (Richard Hughes) - - Add a 'verify' command that verifies the cryptographic hash of device firmware (Richard Hughes) - - Allow clients to add new firmware metadata to the system cache (Richard Hughes) - - Move GetUpdates to the daemon (Richard Hughes) - - Move the LVFS website to the fwupd project (Richard Hughes) - -Bugfixes: - - Accept multiple files at one time when using fwupdmgr dump-rom (Richard Hughes) - - Automatically download metadata using fwupdmgr if required (Richard Hughes) - - Do not return NULL as a gboolean (Thomas Hindoe Paaboel Andersen) - - Don't call efibootmgr after fwupdate (Mario Limonciello) - - Fallback to offline install when calling the update argument (Mario Limonciello) - - Fix Intel VBIOS detection on Dell hardware (Richard Hughes) - - Reload appstream data after refreshing (Mario Limonciello) - - Use the new LVFS GPG key (Richard Hughes) - - Fix build: libgusb is required even without colorhug support (Jussi Kukkonen) - -Version 0.1.3 -~~~~~~~~~~~~~ -Released: 2015-05-28 - -New Features: - - Get the firmware version from the device descriptors (Richard Hughes) - - Run the offline actions using systemd when required (Richard Hughes) - - Support OpenHardware devices using the fwupd vendor extensions (Richard Hughes) - -Bugfixes: - - Add an UNKNOWN status so we can return meaningful enum values (Richard Hughes) - - Coldplug the devices before acquiring the well known name (Richard Hughes) - -Version 0.1.2 -~~~~~~~~~~~~~ -Released: 2015-04-22 - - Add some guidelines for vendors to README (Richard Hughes) - - Only allow signed firmware to be upgraded without a password (Richard Hughes) - -Version 0.1.1 -~~~~~~~~~~~~~ -Released: 2015-03-23 - -New Features: - - Add a 'get-updates' command to fwupdmgr (Richard Hughes) - - Add and document the offline-update lifecycle (Richard Hughes) - - Create a libfwupd shared library (Richard Hughes) - -Bugfixes: - - Create runtime directories if they do not exist (Richard Hughes) - - Do not crash when there are no devices to return (Richard Hughes) - -Version 0.1.0 -~~~~~~~~~~~~~ -Released: 2015-03-16 - -Notes: - - fwupd is a simple daemon to allow session software to update firmware. diff --git a/RELEASE b/RELEASE index 5b9b6224e..6915bf67f 100644 --- a/RELEASE +++ b/RELEASE @@ -1,8 +1,9 @@ fwupd Release Notes -1. Write NEWS entries for fwupd in the same format as usual. +Write release entries: -git shortlog 1.2.0.. | grep -i -v trivial | grep -v Merge > NEWS.new +git log --format="%s" --cherry-pick --right-only 1.2.0... | grep -i -v trivial | grep -v Merge | sort | uniq +Add any user visible changes into data/org.freedesktop.fwupd.metainfo.xml Version 1.2.1 ~~~~~~~~~~~~~ @@ -13,6 +14,7 @@ Bugfixes: Update translations: +appstream-util appdata-to-news data/org.freedesktop.fwupd.metainfo.xml > NEWS ninja-build fwupd-pot tx push --source tx pull --all --force --minimum-perc=5 diff --git a/contrib/debian/docs b/contrib/debian/docs index edc007104..8b1378917 100644 --- a/contrib/debian/docs +++ b/contrib/debian/docs @@ -1 +1 @@ -NEWS + diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index d7e616e5d..dfc036acc 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -202,7 +202,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %systemd_postun_with_restart pesign.service %files -f %{name}.lang -%doc README.md AUTHORS NEWS +%doc README.md AUTHORS %license COPYING %config(noreplace)%{_sysconfdir}/fwupd/daemon.conf %if 0%{?have_uefi} diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 3a45c286d..df7f45045 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -30,4 +30,1030 @@ moderate + + + +

      This release adds the following features:

      +
        +
      • Add a plugin for an upcoming Dell USB-C dock
      • +
      • Add a standalone installer creation script
      • +
      • Add support for devices to show an estimated flash time
      • +
      • Add support for some new Realtek USB devices
      • +
      • Allow firmware files to depend on versions from other devices
      • +
      • Allow setting the version format from a quirk entry
      • +
      • Port from libappstream-glib to libxmlb for a large reduction in RSS
      • +
      • Stop any running daemon over dbus when using fu-tool
      • +
      • Support the Intel ME version format
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add version format quirks for several Lenovo machines
      • +
      • Adjust panamera ESM update routine for some reported issues
      • +
      • Adjust synapticsmst EVB board handling
      • +
      • Check the amount of free space on the ESP
      • +
      • Don't show devices pending a reboot in GetUpgrades
      • +
      • Ensure that parent ID is created before creating quirked children
      • +
      • Optionally wait for replug before updating a device
      • +
      • Set the full AMT device version including the BuildNum
      • +
      • Sort the firmware sack by component priority
      • +
      • Stop showing errors when no Dell dock plugged in
      • +
      • Stop showing the current release during updates in fwupdmgr
      • +
      • Update all sub-devices for a composite update
      • +
      • Use HTTPS_PROXY if set
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • + Add a new device flag 'ignore-validation' that will + override checks +
      • +
      • Add a new plugin to enumerate EC firmware
      • +
      • Add a new plugin to update NVMe hardware
      • +
      • Add a plugin for updating using the flashrom command line tool
      • +
      • Allow the device list to take care of waiting for the device replug
      • +
      • Allow updating just one specific device from the command line
      • +
      • Allow upgrades using a self-signed fwupd.efi binary
      • +
      • Download firmware if the user specifies a URI
      • +
      • Include serial number in daemon device output when trusted
      • +
      • Notify all plugins of device removals through a new vfunc
      • +
      • Use boltd force power API if available
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add an install hook for classic snap
      • +
      • Allow forcing installation even if no AC power is applied
      • +
      • Allow using --force to ignore version_lowest
      • +
      • Always use the same HardwareIDs as Windows
      • +
      • Check the device state before assuming a fake DFU runtime
      • +
      • Copy over parent GUIDs from other plugin donors
      • +
      • Detect location of python3 interpreter
      • +
      • Do not add udev devices after a small delay
      • +
      • Don't fail to run if compiled without GPG/PKCS7
      • +
      • Fix a segfault in fwupdtool caused by cleanup of USB plugins
      • +
      • Implement the systemd recommendations for offline updates
      • +
      • Improve performance when reading keys from the quirk database
      • +
      • Remove children of devices when the parent is removed
      • +
      • Rewrite synapticsmst to use modern error handling
      • +
      • + Rewrite the unifying plugin to use the new daemon-provided + functionality +
      • +
      • Show a time estimate on the progressbar after an update has started
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add support for the Synaptics Panamera hardware
      • +
      • Add validation for Alpine and Titan Ridge
      • +
      • Improve the Redfish plugin to actually work with real hardware
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Allow different plugins to add the same device
      • +
      • Allow flashing unifying devices in recovery mode
      • +
      • Allow running synapticsmst on non-Dell hardware
      • +
      • Check the ESP for sanity at at startup
      • +
      • Do not hold hidraw devices open forever
      • +
      • Don't override _FORTIFY_SOURCE when building the EFI binary
      • +
      • Don't show passwords in fwupdmgr
      • +
      • Fix a potential segfault in smbios data parsing
      • +
      • Fix encoding the GUID into the capsule EFI variable
      • +
      • Fix various bugs when reading the thunderbolt version number
      • +
      • Reboot synapticsmst devices at the end of flash cycle
      • +
      • Show status messages when the daemon is initializing
      • +
      • Show the correct title when updating devices
      • +
      • Show the reasons that plugins are not run on the CLI
      • +
      • Use localedir in po/make-images
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a initial Redfish support
      • +
      • Add a tool to mimic the original fwupdate CLI interface
      • +
      • Allow devices to assign a plugin from the quirk subsystem
      • +
      • Change the quirk file structure to be more efficient
      • +
      • Merge fwupdate functionality into fwupd
      • +
      • + Run a plugin vfunc before and after all the composite devices are + updated +
      • +
      • Support more Wacom tablets
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add release information for locked devices
      • +
      • Allow building with older meson
      • +
      • Detect the EFI system partition location at runtime
      • +
      • Do not use 8bitdo bootloader commands after a successful flash
      • +
      • Enable accesing downloaded files in flatpak and snap
      • +
      • Fix a potential buffer overflow when applying a DFU patch
      • +
      • Fix downgrading older releases to devices
      • +
      • Fix flashing devices that require a manual replug
      • +
      • Fix several small memory leaks in various places
      • +
      • Fix the retrieval of Redfish version
      • +
      • Fix unifying failure to detach when using a slow host controller
      • +
      • Set the Wacom device status when erasing and writing firmware
      • +
      • Show errors in the CLI if unable to access directory
      • +
      • Use the parent device name for Wacom sub-modules
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add an plugin to update some future Wacom tablets
      • +
      • Add 'fwupdmgr get-topology' to show logical device tree
      • +
      • Add support for creating a flatpak
      • +
      • Add support for creating a snap
      • +
      • Add support for Motorola S-record files
      • +
      • Add the Linux Foundation public GPG keys for firmware and metadata
      • +
      • Show a translated warning when the server is limiting downloads
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add a firmware diagnostic tool called fwupdtool
      • +
      • Adjust all licensing to LGPL 2.1+
      • +
      • + Allow installing more than one firmware using 'fwupdmgr + install' +
      • +
      • Allow specifying hwids with OR relationships
      • +
      • Do not call fu_plugin_init() on blacklisted plugins
      • +
      • Do not require libcolorhug to build
      • +
      • Fix a crash in libfwupd where no device ID is set
      • +
      • Fix a potential DoS in libdfu by limiting holes to 1MiB
      • +
      • Fix a segfault that sometimes occurs during cleanup of USB plugins
      • +
      • Fix Hardware-ID{0,1,2,12} compatibility with Microsoft
      • +
      • Hide devices that aren't updatable by default in fwupdmgr
      • +
      • Search all UEFI GUIDs when matching hardware
      • +
      • Stop matching Nintendo Switch Pro in the 8bitdo plugin
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add enable-remote and disable-remote commands to fwupdmgr
      • +
      • Add fu_plugin_add_compile_version() for libraries to use
      • +
      • Allow requiring specific versions of libraries for firmware updates
      • +
      • If no remotes are enabled try to enable the LVFS
      • +
      • Show a warning with interactive prompt when enabling a remote
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Check that EFI system partition is mounted before update
      • +
      • Disable synapticsmst remote control on failure
      • +
      • Don't recoldplug thunderbolt to fix a flashing failure
      • +
      • Fix SQL error when running 'fwupdmgr clear-offline'
      • +
      • Improve the update report message
      • +
      • Only enumerate Dell Docks if the type is known
      • +
      • Only run certtool if a new enough gnutls is present
      • +
      • Prevent a client crash if the daemon somehow sends invalid data
      • +
      • Reboot after scheduling using logind not systemd
      • +
      • Use the right encoding for the label in make-images
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add bash completion for fwupdmgr
      • +
      • Add support for newest Thunderbolt chips
      • +
      • Allow all functions that take device arguments to be prompted
      • +
      • Allow devices to use the runtime version when in bootloader mode
      • +
      • Allow overriding ESP mount point via conf file
      • +
      • Delete any old fwupdate capsules and efivars when launching fwupd
      • +
      • Generate Vala bindings
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Allow ctrl-d out of the prompt for devices
      • +
      • Allow to create package out of provided binary
      • +
      • Correct handling of unknown Thunderbolt devices
      • +
      • Correctly detect new remotes that are manually copied
      • +
      • Fix a crash related to when passing device to downgrade in CLI
      • +
      • Fix running the self tests when no fwupd is installed
      • +
      • Fix Unifying signature writing and parsing for Texas bootloader
      • +
      • Only send success and failure reports to the server
      • +
      • Use a CNAME to redirect to the correct CDN for metadata
      • +
      • Use a longer timeout when powering back the Thunderbolt device
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Offer to reboot when processing an offline update
      • +
      • Report the efivar, libsmbios and fwupdate library versions
      • +
      • Report Thunderbolt safe mode and SecureBoot status
      • +
      • Show the user a URL when they report a known problem
      • +
      • Support split cabinet archives as produced by Windows Update
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Be more careful deleting and modifying device history
      • +
      • Clarify which devices don't have upgrades
      • +
      • Ensure the Thunderbolt version is xx.yy
      • +
      • Fix a daemon warning when using fwupdmgr get-results
      • +
      • Fix crasher with MST flashing
      • +
      • Fix DFU detach with newer releases of libusb
      • +
      • Include the device VID and PID when generating the device-id
      • +
      • Set the RemoteId when using GetDetails
      • +
      • Stop matching 8bitdo DS4 controller VID/PID
      • +
      • Use help2man for dfu-tool and drop docbook dependencies
      • +
      • Use ngettext for any strings with plurals
      • +
      • Use the default value if ArchiveSizeMax is unspecified
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add D-Bus methods to get and modify the history information
      • +
      • Allow the user to share firmware update success or failure
      • +
      • Ask the user to refresh metadata when it is very old
      • +
      • Store firmware update success and failure to a local database
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add a device name for locked UEFI devices
      • +
      • Allow each plugin to opt-in to the recoldplug action
      • +
      • Fix firmware downloading using gnome-software
      • +
      • Fix UX capsule reference to the one specified in efivar
      • +
      • Never add two devices to the daemon with the same ID
      • +
      • Rescan supported flags when refreshing metadata
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a new plugin to add support for CSR 'Driverless DFU'
      • +
      • Add initial SF30/SN30 Pro support
      • +
      • Support AppStream metadata with relative <location> URLs
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add more metadata to the user-agent string
      • +
      • Block owned Dell TPM updates
      • +
      • Choose the correct component from provides matches using requirements
      • +
      • Do not try to parse huge compressed archive files
      • +
      • Fix a double-free bug in the Udev code
      • +
      • Handle Thunderbolt 'native' mode
      • +
      • + Use the new functionality in libgcab >= 1.0 to avoid writing temp + files +
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a plugin for the Nitrokey Storage device
      • +
      • Add support for the original AVR DFU protocol
      • +
      • Allow different plugins to claim the same device
      • +
      • Allow quirks to set common USB properties
      • +
      • Move a common plugin functionality out to a new shared object
      • +
      • Optionally delay the device removal for better replugging
      • +
      • Set environment variables to allow easy per-plugin debugging
      • +
      • Use a SHA1 hash for the internal DeviceID
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add quirk for AT32UC3B1256 as used in the RubberDucky
      • +
      • Disable the dell plugin if libsmbios fails
      • +
      • Don't register for USB UDev events to later ignore them
      • +
      • Fix a possible buffer overflow when debugging ebitdo devices
      • +
      • Fix critical warning when more than one remote fails to load
      • +
      • Fix DFU attaching AVR32 devices like the XMEGA
      • +
      • Ignore useless Thunderbolt device types
      • +
      • Refactor ColorHug into a much more modern plugin
      • +
      • Release the Steelseries interface if getting the version failed
      • +
      • Remove autoconf-isms from the meson configure options
      • +
      • Show a nicer error message if the requirement fails
      • +
      • Sort the output of GetUpgrades correctly
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add support for HWID requirements
      • +
      • Add support for programming various AVR32 and XMEGA parts using DFU
      • +
      • Add the various DFU quirks for the Jabra Speak devices
      • +
      • Allow specifying the output file type for 'dfu-tool read'
      • +
      • Move the database of supported devices out into runtime loaded files
      • +
      • Support the IHEX record type 0x05
      • +
      • Use help2man to generate the man page at build time
      • +
      • Use the new quirk infrastructure for version numbers
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Catch invalid Dell dock component requests
      • +
      • Correctly output Intel HEX files with > 16bit offset addresses
      • +
      • Do not try to verify the element write if upload is unsupported
      • +
      • Fix a double-unref when updating any 8Bitdo device
      • +
      • Fix crash when enumerating with Dell dock connected but with no UEFI
      • +
      • Fix uploading large firmware files over DFU
      • +
      • Format the BCD USB revision numbers correctly
      • +
      • Guess the DFU transfer size if it is not specified
      • +
      • Include the reset timeout as wValue to fix some DFU bootloaders
      • +
      • Make the error message clearer when sans fonts are missing
      • +
      • Support devices with truncated DFU interface data
      • +
      • + Use the correct remote-specified username and passord when using + fwupdmgr +
      • +
      • Use the correct wDetachTimeOut when writing DFU firmware
      • +
      • Verify devices with legacy VIDs are actually 8Bitdo controllers
      • +
      +
      +
      + + +

      This release breaks API and ABI to remove deprecated symbols!

      +

      This release adds the following features:

      +
        +
      • Add a human-readable title for each remote
      • +
      • Add a method to return a list of upgrades for a specific device
      • +
      • + Add an 'Summary' and 'Icons' properties to each + device +
      • +
      • Add FuDeviceLocker to simplify device open/close lifecycles
      • +
      • Add functionality to blacklist Dell HW with problems
      • +
      • Add fu_plugin_check_supported()
      • +
      • Add fwupd_remote_get_checksum() to use in client programs
      • +
      • Add ModifyRemote as an easy way to enable and disable remotes
      • +
      • Add the plugin documentation to the main gtk-doc
      • +
      • Allow plugins to depend on each other
      • +
      • Disable the fallback USB plugin
      • +
      • Parse the SMBIOS v2 and v3 DMI tables directly
      • +
      • Support uploading the UEFI firmware splash image
      • +
      • Use the intel-wmi-thunderbolt kernel module to force power
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Only run SMI to toggle host MST GPIO on Dell systems with host MST
      • +
      • Disable unifying support if no CONFIG_HIDRAW support
      • +
      • Do not auto-open all USB devices at startup
      • +
      • Do not fail to load the daemon if cached metadata is invalid
      • +
      • Do not use system-specific infomation for UEFI PCI devices
      • +
      • Fix a crash when using fu_plugin_device_add_delay()
      • +
      • Fix the libdfu self test failure on s390 and ppc64
      • +
      • Fix various printing issues with the progressbar
      • +
      • Generate the LD script from the GObject introspection data
      • +
      • Never fallback to an offline update from client code
      • +
      • Only set the Dell coldplug delay when we know we need it
      • +
      • Prefer to use HWIDs to get DMI keys and DE table
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a configure switch for the LVFS remotes
      • +
      • Add a FirmwareBaseURI parameter to the remote config
      • +
      • Add a firmware builder that uses bubblewrap
      • +
      • + Add a python script to create fwupd compatible cab files from + Microsoft .exe files +
      • +
      • Add a thunderbolt plugin for new kernel interface
      • +
      • Allow plugins to get DMI data from the hardware in a safe way
      • +
      • Allow plugins to set metadata on devices created by other plugins
      • +
      • Optionally install the LVFS PKCS7 root certificate
      • +
      • Optionally use GnuTLS to verify PKCS7 certificates
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add back options for HAVE_SYNAPTICS and HAVE_THUNDERBOLT
      • +
      • Allow configuring systemd and udev directories
      • +
      • Enable C99 support in meson.build
      • +
      • Fix an incomplete cipher when using XTEA on data not in 4 byte chunks
      • +
      • Fix minor const-correctness issues
      • +
      • Implement thunderbolt image validation
      • +
      • Remove the confusing ALLOW_OFFLINE and ALLOW_ONLINE flags
      • +
      • Show a bouncing progress bar if the percentage remains at zero
      • +
      • Use a hwid to match supported systems for synapticsmst
      • +
      • Use the new bootloader PIDs for Unifying pico receivers
      • +
      • When thunderbolt is in safe mode on a Dell recover using SMBIOS
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add DfuPatch to support forward-only firmware patching
      • +
      • Add --version option to fwupdmgr
      • +
      • Display all errors recorded by efi_error tracing
      • +
      • Make building introspection optional
      • +
      • Support embedded devices with local firmware metadata
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Check all the device GUIDs against the blacklist when added
      • +
      • Correct a memory leak in Dell plugin
      • +
      • Default to 'en' for UEFI capsule graphics
      • +
      • Don't log a warning when an unknown unifying report is parsed
      • +
      • Enable test suite via /etc/fwupd.conf
      • +
      • Fix a hang on 32 bit computers
      • +
      • Fix compilation of the policy on a variety of configurations
      • +
      • Fix UEFI crash when the product name is NULL
      • +
      • Make flashing ebitdo devices work with fu-ebitdo-tool
      • +
      • Make messages from installing capsules useful
      • +
      • Make sure the unifying percentage completion goes from 0% to 100%
      • +
      • Run the plugin coldplug methods in a predictable order
      • +
      • Test UEFI for kernel support during coldplug
      • +
      • Use new GUsb functionality to fix flashing Unifying devices
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a get-remotes command to fwupdmgr
      • +
      • Add a plugin to get the version of the AMT ME interface
      • +
      • Add Arch Linux to CI
      • +
      • Add some installed tests flashing actual hardware
      • +
      • Allow flashing Unifying devices in bootloader modes
      • +
      • Allow ordering the metadata remotes
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Do not check the runtime if the DFU device is in bootloader mode
      • +
      • Do not unlock devices when doing VerifyUpdate
      • +
      • Filter by Unifying SwId when making HID++2.0 requests
      • +
      • Fix downgrades when version_lowest is set
      • +
      • Fix the self tests when running on PPC64 big endian
      • +
      • Move the remotes parsing from the client to the server
      • +
      • Split up the Unifying HID++2.0 and HID++1.0 functionality
      • +
      • Store the metadata files rather than merging to one store
      • +
      • Use a longer timeout for some Unifying operations
      • +
      • Use the UFY DeviceID prefix for Unifying devides
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add installed tests that use the daemon
      • +
      • Add the ability to restrict firmware to specific vendors
      • +
      • Enable Travis CI for Fedora and Debian
      • +
      • Export some more API for dealing with checksums
      • +
      • Generate a images for status messages during system firmware update
      • +
      • Show progress download when refreshing metadata
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Compile with newer versions of meson
      • +
      • Ensure that firmware provides are legal GUIDs
      • +
      • Fix a common crash when refreshing metadata
      • +
      • Use the correct type signature in the D-Bus introspection file
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a 'downgrade' command to fwupdmgr
      • +
      • Add a 'get-releases' command to fwupdmgr
      • +
      • Add support for ConsoleKit2
      • +
      • Add support for Microsoft HardwareIDs
      • +
      • Allow downloading metadata from more than just the LVFS
      • +
      • Allow multiple checksums on devices and releases
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Allow to specify bindir
      • +
      • Correctly open Unifying devices with original factory firmware
      • +
      • Deprecate some of the old FwupdResult API
      • +
      • Do not copy the origin from the new metadata file
      • +
      • Do not expect a Unifying reply when issuing a REBOOT command
      • +
      • Do not re-download firmware that exists in the cache
      • +
      • Fix a problem when testing for a Dell system
      • +
      • Fix flashing new firmware to 8bitdo controllers
      • +
      • Increase minimum required AppStream-Glib version to 0.6.13
      • +
      • Make documentation and man pages optional
      • +
      • Make systemd dependency at least version 231
      • +
      • Only decompress the firmware after the signature check
      • +
      • Remove 'lib' prefix when looking for libraries
      • +
      • Return the remote ID when getting updates about hardware
      • +
      • Send the daemon the remote ID when sending firmware metadata
      • +
      +
      +
      + + +

      This release adds the following feature:

      +
        +
      • Add support for Unifying DFU features
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Do not spew a critial warning when parsing an invalid URI
      • +
      • Ensure device is closed if did not complete setup
      • +
      • Ensure steelseries device is closed if it returns an invalid packet
      • +
      • Fix man page installation location
      • +
      • Ignore spaces in the Unifying version prefix
      • +
      • Set HAVE_POLKIT_0_114 when polkit is newer than 0.114
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a config option to allow runtime disabling plugins by name
      • +
      • Add the Meson build system and remove autotools
      • +
      • Support signed Intel HEX files
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add DFU quirk for OpenPICC and SIMtrace
      • +
      • Create directories in /var/cache as required
      • +
      • Refactor the unifying plugin now we know more about the hardware
      • +
      • Set the source origin when saving metadata
      • +
      • Support proxy servers in fwupdmgr
      • +
      • Use a 60 second timeout on all client downloads
      • +
      +
      +
      + + +

      This release fixes the following bugs:

      +
        +
      • Adjust systemd confinement restrictions
      • +
      • Do not hardcode docbook2man path
      • +
      • Don't initialize libsmbios on unsupported systems
      • +
      • Fix a crash when enumerating devices on a Dell WLD15
      • +
      • Fix compiler warnings
      • +
      • Fix fwupdmgr timeout with missing pending database
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a set of vfuncs that are run before and after a device update
      • +
      • + Add Dell-specific functionality to allow other plugins turn on + TBT/GPIO +
      • +
      • Add support for Intel Thunderbolt devices
      • +
      • Add support for Logitech Unifying devices
      • +
      • Add support for Synaptics MST cascades hubs
      • +
      • Add support for the Altus-Metrum ChaosKey device
      • +
      • Add VerifyUpdate to update the device checksums server-side
      • +
      • + Allow the metadata to match a version of fwupd and the existing fw + version +
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add a new method for forcing a controller to flash mode
      • +
      • Always make sure we're getting a C99 compiler
      • +
      • Close USB devices before error returns
      • +
      • Don't read data from some DfuSe targets
      • +
      • Include all debug messages when run with --verbose
      • +
      • Return the pending UEFI update when not on AC power
      • +
      • + Use a heuristic for the start address if the firmware has no DfuSe + footer +
      • +
      • Use more restrictive settings when running under systemd
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a 'replace-data' command to dfu-tool
      • +
      • Use an animated progress bar when performing DFU operations
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add quirks for HydraBus as it does not have a DFU runtime
      • +
      • + Don't create the UEFI dummy device if the unlock will happen on + next boot +
      • +
      • Enable hardening flags on more binaries
      • +
      • Fix an assert when unlocking the dummy ESRT device
      • +
      • Fix writing firmware to devices using the ST reference bootloader
      • +
      • Match the Dell TB16 device
      • +
      • Re-get the quirks when the DfuDevice gets a new GUsbDevice
      • +
      • Show the nicely formatted target name for DfuSe devices
      • +
      • Verify devices support updating in mode they are called
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add dfu_firmware_add_symbol()
      • +
      • Allow the argument to 'dfu-tool set-release' be major.minor
      • +
      • Load the Altos USB descriptor from ELF files
      • +
      • Support writing the IHEX symbol table
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add a fallback for older appstream-glib releases
      • +
      • Fix a possible crash when uploading firmware files using libdfu
      • +
      • Fix libfwupd self tests when a host-provided fwupd is not available
      • +
      • + Show the human-readable version in the 'dfu-tool dump' + output +
      • +
      • Write the ELF files with the correct section type
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a set-address and set-target-size commands to dfu-util
      • +
      • Add a small library for talking with 0bitdo hardware
      • +
      • Add Dell TPM and TB15/WD15 support via new Dell provider
      • +
      • Add FU_DEVICE_FLAG_NEEDS_BOOTLOADER
      • +
      • Add fwupd_client_get_status()
      • +
      • Add fwupd_result_get_unique_id()
      • +
      • Add initial ELF reading and writing support to libdfu
      • +
      • Add support for installing multiple devices from a CAB file
      • +
      • Allow providers to export percentage completion
      • +
      • Show a progress notification when installing firmware
      • +
      • Show the vendor flashing instructions when installing
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add XPS 9250 to Dell TPM modeswitch blacklist
      • +
      • Allow blacklisting devices by their GUID
      • +
      • Conditionally enable all providers based upon installed
      • +
      • Display flashes left in results output when it gets low
      • +
      • Do not attempt to add DFU devices not in runtime mode
      • +
      • Do not use the deprecated GNOME_COMPILE_WARNINGS
      • +
      • Don't fail while checking versions or locked state
      • +
      • Embed fwupd version in generated documentation
      • +
      • Ensure the ID is set when getting local firmware details
      • +
      • Fix gtk-doc build when srcdir != builddir
      • +
      • Fix libdfu hang when parsing corrupt IHEX files
      • +
      • Ignore devices that do not add at least one GUID
      • +
      • In get-details output, display the blob filename
      • +
      • Save the unique ID in the pending database
      • +
      • Support the 'DEVO' cipher kind in libdfu
      • +
      • Switch to the Amazon S3 CDN for firmware metadata
      • +
      • Update fwupdmgr manpage for new commands and arguments
      • +
      • Use a private gnupg key store
      • +
      • Use the correct firmware when installing a composite device
      • +
      • Use the SHA1 hash of the local file data as the origin
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a GetDetailsLocal() method to eventually replace GetDetails()
      • +
      • Add fu_device_get_alternate()
      • +
      • Allow devices to have multiple assigned GUIDs
      • +
      • Allow metainfo files to match only specific revisions of devices
      • +
      • Show the DFU protocol version in 'dfu-tool list'
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Enforce allowing providers to take away flash abilities
      • +
      • Only claim the DFU interface when required
      • +
      • Only return updatable devices from GetDevices()
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a --force flag to override provider warnings
      • +
      • Add device-added, device-removed and device-changed signals
      • +
      • Add dfu_image_get_element_default()
      • +
      • Add for a new device field 'Flashes Left'
      • +
      • Add fwupd_client_connect()
      • +
      • Add the 'monitor' debugging command for fwupdmgr
      • +
      • Add the 'supported' flag to the FuDevice
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add summary and name field for Rival SteelSeries
      • +
      • Fix a critical warning when restarting the daemon
      • +
      • Fix BE issues when reading and writing DFU files
      • +
      • Make the device display name nicer
      • +
      • Match the AppStream metadata after a device has been added
      • +
      • Remove non-interactive pinentry setting from fu-keyring
      • +
      • Return all update descriptions newer than the installed version
      • +
      • Set the device description when parsing local firmware files
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add a version plugin for SteelSeries hardware
      • +
      • Add FwupdClient and FwupdResult to libfwupd
      • +
      • Generate gtk-doc documentation for libfwupd
      • +
      • Return the device flags when getting firmware details
      • +
      • Support other checksum kinds
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add Alienware to the version quirk table
      • +
      • Allow the test suite to run in %check
      • +
      • Do not return updates that require AC when on battery
      • +
      • Do not use /tmp for downloaded files
      • +
      • Test that GPG key import actually was successful
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add an unlock method for devices
      • +
      • Add a simple plugin infrastructure
      • +
      • Add ESRT enable method into UEFI provider
      • +
      • Install the hardcoded firmware AppStream file
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Correct the BCD version number for DFU 1.1
      • +
      • Do not use deprecated API from libappstream-glib
      • +
      • Ignore the DFU runtime on the DW1820A
      • +
      • Only read PCI OptionROM firmware when devices are manually unlocked
      • +
      • Require AC power before scheduling some types of firmware update
      • +
      • Show ignored DFU devices in dfu-util, but not in fwupd
      • +
      +
      +
      + + +

      This release adds the following feature:

      +
        +
      • + Add 'Created' and 'Modified' properties on + managed devices +
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Fix get-results for UEFI provider
      • +
      • Support vendor-specific UEFI version encodings
      • +
      +
      +
      + + +

      This release fixes the following bugs:

      +
        +
      • Always persist ColorHug devices after replug
      • +
      • Do not misdetect different ColorHug devices
      • +
      • Only dump the profiling data when run with --verbose
      • +
      +
      +
      + + +

      + This release adds a new GObject library called libdfu and a command + line client called dfu-tool. This is a low-level tool used to upgrade + USB device firmware and can either be shipped in the same package as + fwupd or split off as separate subpackages. +

      +

      This release adds the following feature:

      +
        +
      • Add support for automatically updating USB DFU-capable devices
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Emit the changed signal after doing an update
      • +
      • Export the AppStream ID when returning device results
      • +
      • Fix compile with --disable-shared
      • +
      • Use new API available in fwup 0.5
      • +
      • Use the same device identification string format as Microsoft
      • +
      +
      +
      + + +

      This release fixes the following bugs:

      +
        +
      • Avoid seeking when reading the file magic during refresh
      • +
      • Do not assume that the compressed XML data will be NUL terminated
      • +
      • Use the correct user agent string for fwupdmgr
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Add profiling data to debug slow startup times
      • +
      • Support cabinet archives files with more than one firmware
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add the update description to the GetDetails results
      • +
      • + Clear the in-memory firmware store only after parsing a valid XML + file +
      • +
      • Ensure D-Bus remote errors are registered at fwupdmgr startup
      • +
      • + Fix verify-update to produce components with the correct provide + values +
      • +
      • Require appstream-glib 0.5.1
      • +
      • Show the dotted-decimal representation of the UEFI version number
      • +
      • + When the version is from the 'FW' extension do not cache + the device +
      • +
      +
      +
      + + +

      This release fixes the following bugs:

      +
        +
      • Fix the error message when no devices can be updated
      • +
      • Fix reading symlink to prevent crash with some compilers
      • +
      +
      +
      + + +

      This release adds the following feature:

      +
        +
      • Raise the dep on GLib to support and use g_autoptr()
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Do not merge existing firmware metadata
      • +
      • Do not reboot if racing with the PackageKit offline update mechanism
      • +
      +
      +
      + + +

      This release adds the following feature:

      +
        +
      • Remove fwsignd, we have the LVFS now
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add application metadata when getting the updates list
      • +
      • Depend on appstream-glib >= 0.5.0
      • +
      • Don't apply firmware if something else is processing the update
      • +
      • Install fwupd into /usr/lib/$(triplet)/fwupd instead
      • +
      • Simplify the version properties on devices to avoid complexity
      • +
      • Update the offline update service to invoke right command
      • +
      • Use the new secure metadata URI
      • +
      +
      +
      + + +

      + For the device verification code to work correctly you need at least + libappstream-glib 0.5.0 installed. +

      +

      This release adds the following features:

      +
        +
      • Add a Raspberry Pi firmware provider
      • +
      • Add a simple config file to store the correct LVFS download URI
      • +
      • Make parsing the option ROM runtime optional
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Allow fwupd to be autostarted by systemd
      • +
      • + Allow no arguments to 'fwupdmgr verify-update' and use sane + defaults +
      • +
      • Devices with option ROM are always internal
      • +
      • Do not pre-convert the update description from AppStream XML
      • +
      • Fix validation of written firmware
      • +
      • Move the verification and metadata matching phase to the daemon
      • +
      • Sign the test binary with the correct key
      • +
      • Use the AppStream 0.9 firmware specification by default
      • +
      +
      +
      + + +

      + In this release we've moved the LVFS website to the fwupd project + and made them work really well together. To update all the firmware on + your system is now just a case of 'fwupdmgr refresh && + fwupdmgr update'. + We've also added verification of BIOS and PCI ROM firmware, which + may be useful for forensics or to verify that system updates have been + applied. +

      +

      This release adds the following features:

      +
        +
      • Actually parse the complete PCI option ROM
      • +
      • + Add a 'fwupdmgr update' command to update all devices to + latest versions +
      • +
      • Add a simple signing server that operates on .cab files
      • +
      • + Add a 'verify' command that verifies the cryptographic hash + of device firmware +
      • +
      • Allow clients to add new firmware metadata to the system cache
      • +
      • Move GetUpdates to the daemon
      • +
      • Move the LVFS website to the fwupd project
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Accept multiple files at one time when using fwupdmgr dump-rom
      • +
      • Automatically download metadata using fwupdmgr if required
      • +
      • Do not return NULL as a gboolean
      • +
      • Don't call efibootmgr after fwupdate
      • +
      • Fallback to offline install when calling the update argument
      • +
      • Fix Intel VBIOS detection on Dell hardware
      • +
      • Reload appstream data after refreshing
      • +
      • Use the new LVFS GPG key
      • +
      • Fix build: libgusb is required even without colorhug support
      • +
      +
      +
      + + +

      This release adds the following features:

      +
        +
      • Get the firmware version from the device descriptors
      • +
      • Run the offline actions using systemd when required
      • +
      • Support OpenHardware devices using the fwupd vendor extensions
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Add an UNKNOWN status so we can return meaningful enum values
      • +
      • Coldplug the devices before acquiring the well known name
      • +
      +
      +
      + + + + + + +

      This release adds the following features:

      +
        +
      • Add a 'get-updates' command to fwupdmgr
      • +
      • Add and document the offline-update lifecycle
      • +
      • Create a libfwupd shared library
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Create runtime directories if they do not exist
      • +
      • Do not crash when there are no devices to return
      • +
      +
      +
      + + +

      fwupd is a simple daemon to allow session software to update firmware.

      +
      +
      +
      From 634da0373014cf517e1260683dc09eb5247ab1b7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 5 Nov 2018 11:42:20 +0000 Subject: [PATCH 090/254] Create a silo index to speed up GUID queries This speeds up matching for GUIDs by about 90%, taking the query from 3.17ms to about 0.33ms on my Thinkpad. This is more important for slow ARM hardware, where strcmp() is more expensive than on x64. --- contrib/ci/Dockerfile-fedora.in | 2 +- meson.build | 2 +- src/fu-engine.c | 14 ++++++++++++-- subprojects/libxmlb.wrap | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index 99dd1690b..75f5434c1 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -5,7 +5,7 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id RUN dnf --enablerepo=updates-testing -y update -RUN dnf install -y https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.3/1.fc29/x86_64/libxmlb-0.1.3-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.3/1.fc29/x86_64/libxmlb-devel-0.1.3-1.fc29.x86_64.rpm +RUN dnf install -y https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.5/1.fc29/x86_64/libxmlb-0.1.5-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.5/1.fc29/x86_64/libxmlb-devel-0.1.5-1.fc29.x86_64.rpm RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN mkdir /build diff --git a/meson.build b/meson.build index 89cb408c9..16c76caa8 100644 --- a/meson.build +++ b/meson.build @@ -154,7 +154,7 @@ gudev = dependency('gudev-1.0') if gudev.version().version_compare('>= 232') conf.set('HAVE_GUDEV_232', '1') endif -libxmlb = dependency('xmlb', version : '>= 0.1.3', fallback : ['libxmlb', 'libxmlb_dep']) +libxmlb = dependency('xmlb', version : '>= 0.1.5', fallback : ['libxmlb', 'libxmlb_dep']) gusb = dependency('gusb', version : '>= 0.2.9') sqlite = dependency('sqlite3') libarchive = dependency('libarchive') diff --git a/src/fu-engine.c b/src/fu-engine.c index 179989842..3d2d3442d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1860,6 +1860,16 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) if (components != NULL) g_debug ("%u components now in silo", components->len); + /* build the index */ + if (!xb_silo_query_build_index (self->silo, + "components/component/provides/firmware", + "type", error)) + return FALSE; + if (!xb_silo_query_build_index (self->silo, + "components/component/provides/firmware", + NULL, error)) + return FALSE; + /* did any devices SUPPORTED state change? */ devices = fu_device_list_get_all (self->device_list); for (guint i = 0; i < devices->len; i++) { @@ -2076,7 +2086,7 @@ fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError * dev = fwupd_device_new (); provides = xb_node_query (component, - "provides/firmware[@type='flashed']", + "provides/firmware[@type=$'flashed']", 0, &error_local); if (provides == NULL) { g_set_error (error, @@ -2480,7 +2490,7 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er const gchar *guid = g_ptr_array_index (device_guids, i); xb_string_append_union (xpath, "components/component/" - "provides/firmware[@type='flashed'][text()='%s']/" + "provides/firmware[@type=$'flashed'][text()=$'%s']/" "../..", guid); } components = xb_silo_query (self->silo, xpath->str, 0, &error_local); diff --git a/subprojects/libxmlb.wrap b/subprojects/libxmlb.wrap index f64c8a729..4894da302 100644 --- a/subprojects/libxmlb.wrap +++ b/subprojects/libxmlb.wrap @@ -1,4 +1,4 @@ [wrap-git] directory = libxmlb url = https://github.com/hughsie/libxmlb.git -revision = 0.1.3 +revision = 0.1.5 From 75b965d01d80d70ae51816acd4d4cafdaf792e99 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 15 Nov 2018 13:51:21 +0000 Subject: [PATCH 091/254] Shut down the daemon after 2h of inactivity Plugins are allowed to 'opt-out' of this behaviour using _RULE_INHIBITS_IDLE. This should be used where waking up the hardware to coldplug is expensive, either from a power consumption point of view, or if other artifacts are going to be seem -- for instance if the screen flickers when probing display devices. This functionality is also inhibited when the actual upgrade is happening, for obvious reasons. Admins can turn off this auto-sleep behaviour by editing the daemon.conf file. Fixes https://github.com/hughsie/fwupd/issues/417 --- data/daemon.conf | 6 + libfwupd/fwupd-enums.c | 4 + libfwupd/fwupd-enums.h | 2 + plugins/synapticsmst/fu-plugin-synapticsmst.c | 4 + plugins/thunderbolt/fu-plugin-thunderbolt.c | 4 + src/fu-config.c | 17 ++ src/fu-config.h | 1 + src/fu-engine.c | 45 ++++ src/fu-engine.h | 1 + src/fu-idle.c | 237 ++++++++++++++++++ src/fu-idle.h | 44 ++++ src/fu-main.c | 10 + src/fu-plugin.c | 8 + src/fu-plugin.h | 5 +- src/meson.build | 3 + 15 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 src/fu-idle.c create mode 100644 src/fu-idle.h diff --git a/data/daemon.conf b/data/daemon.conf index 51ab19f4c..e5065fe9b 100644 --- a/data/daemon.conf +++ b/data/daemon.conf @@ -10,3 +10,9 @@ BlacklistPlugins=test # Maximum archive size that can be loaded in Mb, with 0 for the default ArchiveSizeMax=0 + +# Idle time in seconds to shut down the daemon -- note some plugins might +# inhibit the auto-shutdown, for instance thunderbolt. +# +# A value of 0 specifies 'never' +IdleTimeout=7200 diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index 6475159b6..9154d955a 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -57,6 +57,8 @@ fwupd_status_to_string (FwupdStatus status) return "downloading"; if (status == FWUPD_STATUS_WAITING_FOR_AUTH) return "waiting-for-auth"; + if (status == FWUPD_STATUS_SHUTDOWN) + return "shutdown"; return NULL; } @@ -99,6 +101,8 @@ fwupd_status_from_string (const gchar *status) return FWUPD_STATUS_DEVICE_BUSY; if (g_strcmp0 (status, "waiting-for-auth") == 0) return FWUPD_STATUS_WAITING_FOR_AUTH; + if (g_strcmp0 (status, "shutdown") == 0) + return FWUPD_STATUS_SHUTDOWN; return FWUPD_STATUS_LAST; } diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 708c4b3d4..32f218f7d 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -24,6 +24,7 @@ * @FWUPD_STATUS_DEVICE_ERASE: Erasing a device * @FWUPD_STATUS_WAITING_FOR_AUTH: Waiting for authentication * @FWUPD_STATUS_DEVICE_BUSY: The device is busy + * @FWUPD_STATUS_SHUTDOWN: The daemon is shutting down * * The flags to show daemon status. **/ @@ -41,6 +42,7 @@ typedef enum { FWUPD_STATUS_DEVICE_ERASE, /* Since: 1.0.0 */ FWUPD_STATUS_WAITING_FOR_AUTH, /* Since: 1.0.0 */ FWUPD_STATUS_DEVICE_BUSY, /* Since: 1.0.1 */ + FWUPD_STATUS_SHUTDOWN, /* Since: 1.2.1 */ /*< private >*/ FWUPD_STATUS_LAST } FwupdStatus; diff --git a/plugins/synapticsmst/fu-plugin-synapticsmst.c b/plugins/synapticsmst/fu-plugin-synapticsmst.c index 780064834..f30b6c7ac 100644 --- a/plugins/synapticsmst/fu-plugin-synapticsmst.c +++ b/plugins/synapticsmst/fu-plugin-synapticsmst.c @@ -171,6 +171,10 @@ fu_plugin_synaptics_add_device (FuPlugin *plugin, fu_plugin_device_add (plugin, dev); fu_plugin_cache_add (plugin, dev_id_str, dev); + + /* inhibit the idle sleep of the daemon */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE, + "SynapticsMST can cause the screen to flash when probing"); return TRUE; } diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index d04e1ea68..8316af9e0 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -354,6 +354,10 @@ fu_plugin_thunderbolt_add (FuPlugin *plugin, GUdevDevice *device) fu_plugin_cache_add (plugin, id, dev); fu_plugin_device_add (plugin, dev); + + /* inhibit the idle sleep of the daemon */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE, + "thunderbolt requires device wakeup"); } static void diff --git a/src/fu-config.c b/src/fu-config.c index f3cad88aa..04e4e34fe 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -31,6 +31,7 @@ struct _FuConfig GPtrArray *blacklist_devices; GPtrArray *blacklist_plugins; guint64 archive_size_max; + guint idle_timeout; XbSilo *silo; GHashTable *os_release; }; @@ -353,6 +354,7 @@ fu_config_load_from_file (FuConfig *self, const gchar *config_file, { GFileMonitor *monitor; guint64 archive_size_max; + guint idle_timeout; g_auto(GStrv) devices = NULL; g_auto(GStrv) plugins = NULL; g_autoptr(GFile) file = NULL; @@ -410,6 +412,14 @@ fu_config_load_from_file (FuConfig *self, const gchar *config_file, NULL); if (archive_size_max > 0) self->archive_size_max = archive_size_max *= 0x100000; + + /* get idle timeout */ + idle_timeout = g_key_file_get_uint64 (self->keyfile, + "fwupd", + "IdleTimeout", + NULL); + if (idle_timeout > 0) + self->idle_timeout = idle_timeout; return TRUE; } @@ -506,6 +516,13 @@ fu_config_get_remotes (FuConfig *self) return self->remotes; } +guint +fu_config_get_idle_timeout (FuConfig *self) +{ + g_return_val_if_fail (FU_IS_CONFIG (self), 0); + return self->idle_timeout; +} + FwupdRemote * fu_config_get_remote_by_id (FuConfig *self, const gchar *remote_id) { diff --git a/src/fu-config.h b/src/fu-config.h index 8602f883f..a429cf32b 100644 --- a/src/fu-config.h +++ b/src/fu-config.h @@ -21,6 +21,7 @@ gboolean fu_config_load (FuConfig *self, GError **error); guint64 fu_config_get_archive_size_max (FuConfig *self); +guint fu_config_get_idle_timeout (FuConfig *self); GPtrArray *fu_config_get_blacklist_devices (FuConfig *self); GPtrArray *fu_config_get_blacklist_plugins (FuConfig *self); GPtrArray *fu_config_get_remotes (FuConfig *self); diff --git a/src/fu-engine.c b/src/fu-engine.c index 3d2d3442d..77bc05ab1 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -32,6 +32,7 @@ #include "fu-device-private.h" #include "fu-engine.h" #include "fu-hwids.h" +#include "fu-idle.h" #include "fu-keyring-utils.h" #include "fu-history.h" #include "fu-mutex.h" @@ -56,6 +57,7 @@ struct _FuEngine FwupdStatus status; guint percentage; FuHistory *history; + FuIdle *idle; XbSilo *silo; gboolean coldplug_running; guint coldplug_id; @@ -88,6 +90,7 @@ static void fu_engine_emit_changed (FuEngine *self) { g_signal_emit (self, signals[SIGNAL_CHANGED], 0); + fu_engine_idle_reset (self); } static void @@ -1079,6 +1082,12 @@ fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, return TRUE; } +void +fu_engine_idle_reset (FuEngine *self) +{ + fu_idle_reset (self->idle); +} + static gchar * fu_engine_get_boot_time (void) { @@ -1208,9 +1217,14 @@ fu_engine_install_tasks (FuEngine *self, FwupdInstallFlags flags, GError **error) { + g_autoptr(FuIdleLocker) locker = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) devices_new = NULL; + /* do not allow auto-shutdown during this time */ + locker = fu_idle_locker_new (self->idle, "performing update"); + g_assert (locker != NULL); + /* 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++) { @@ -3099,6 +3113,17 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED); } +static void +fu_engine_plugin_rules_changed_cb (FuPlugin *plugin, gpointer user_data) +{ + FuEngine *self = FU_ENGINE (user_data); + GPtrArray *rules = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE); + for (guint j = 0; j < rules->len; j++) { + const gchar *tmp = g_ptr_array_index (rules, j); + fu_idle_inhibit (self->idle, tmp); + } +} + static void fu_engine_plugin_device_removed_cb (FuPlugin *plugin, FuDevice *device, @@ -3433,6 +3458,9 @@ fu_engine_load_plugins (FuEngine *self, GError **error) g_signal_connect (plugin, "check-supported", G_CALLBACK (fu_engine_plugin_check_supported_cb), self); + g_signal_connect (plugin, "rules-changed", + G_CALLBACK (fu_engine_plugin_rules_changed_cb), + self); /* add */ fu_plugin_list_add (self->plugin_list, plugin); @@ -3720,6 +3748,10 @@ fu_engine_load (FuEngine *self, GError **error) return FALSE; } + /* set up idle exit */ + if ((self->app_flags & FU_APP_FLAGS_NO_IDLE_SOURCES) == 0) + fu_idle_set_timeout (self->idle, fu_config_get_idle_timeout (self->config)); + /* load quirks, SMBIOS and the hwids */ fu_engine_load_smbios (self); fu_engine_load_hwids (self); @@ -3849,6 +3881,14 @@ fu_engine_add_runtime_version (FuEngine *self, g_strdup (version)); } +static void +fu_engine_idle_status_notify_cb (FuIdle *idle, GParamSpec *pspec, FuEngine *self) +{ + FwupdStatus status = fu_idle_get_status (idle); + if (status == FWUPD_STATUS_SHUTDOWN) + fu_engine_set_status (self, status); +} + static void fu_engine_init (FuEngine *self) { @@ -3858,6 +3898,7 @@ fu_engine_init (FuEngine *self) self->device_list = fu_device_list_new (); self->smbios = fu_smbios_new (); self->hwids = fu_hwids_new (); + self->idle = fu_idle_new (); self->quirks = fu_quirks_new (); self->history = fu_history_new (); self->plugin_list = fu_plugin_list_new (); @@ -3866,6 +3907,9 @@ fu_engine_init (FuEngine *self) self->runtime_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->compile_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_signal_connect (self->idle, "notify::status", + G_CALLBACK (fu_engine_idle_status_notify_cb), self); + /* add some runtime versions of things the daemon depends on */ fu_engine_add_runtime_version (self, "org.freedesktop.fwupd", VERSION); fu_engine_add_runtime_version (self, "com.redhat.fwupdate", "12"); @@ -3903,6 +3947,7 @@ fu_engine_finalize (GObject *obj) if (self->coldplug_id != 0) g_source_remove (self->coldplug_id); + g_object_unref (self->idle); g_object_unref (self->config); g_object_unref (self->smbios); g_object_unref (self->quirks); diff --git a/src/fu-engine.h b/src/fu-engine.h index d276206f2..b21d84075 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -25,6 +25,7 @@ G_DECLARE_FINAL_TYPE (FuEngine, fu_engine, FU, ENGINE, GObject) FuEngine *fu_engine_new (FuAppFlags app_flags); void fu_engine_add_plugin_filter (FuEngine *self, const gchar *plugin_glob); +void fu_engine_idle_reset (FuEngine *self); gboolean fu_engine_load (FuEngine *self, GError **error); gboolean fu_engine_load_plugins (FuEngine *self, diff --git a/src/fu-idle.c b/src/fu-idle.c new file mode 100644 index 000000000..17b03720a --- /dev/null +++ b/src/fu-idle.c @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuIdle" + +#include "config.h" + +#include + +#include "fu-idle.h" +#include "fu-mutex.h" + +static void fu_idle_finalize (GObject *obj); + +struct _FuIdle +{ + GObject parent_instance; + GPtrArray *items; /* of FuIdleItem */ + FuMutex *items_mutex; + guint idle_id; + guint timeout; + FwupdStatus status; +}; + +enum { + PROP_0, + PROP_STATUS, + PROP_LAST +}; + +static void +fu_idle_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + FuIdle *self = FU_IDLE (object); + switch (prop_id) { + case PROP_STATUS: + g_value_set_uint (value, self->status); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_idle_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +typedef struct { + gchar *reason; + guint32 token; +} FuIdleItem; + +G_DEFINE_TYPE (FuIdle, fu_idle, G_TYPE_OBJECT) + +FwupdStatus +fu_idle_get_status (FuIdle *self) +{ + g_return_val_if_fail (FU_IS_IDLE (self), FWUPD_STATUS_UNKNOWN); + return self->status; +} + +static void +fu_idle_set_status (FuIdle *self, FwupdStatus status) +{ + if (self->status == status) + return; + self->status = status; + g_debug ("status now %s", fwupd_status_to_string (status)); + g_object_notify (G_OBJECT (self), "status"); +} + +static gboolean +fu_idle_check_cb (gpointer user_data) +{ + FuIdle *self = FU_IDLE (user_data); + fu_idle_set_status (self, FWUPD_STATUS_SHUTDOWN); + return G_SOURCE_CONTINUE; +} + +static void +fu_idle_start (FuIdle *self) +{ + if (self->idle_id != 0) + return; + if (self->timeout == 0) + return; + self->idle_id = g_timeout_add_seconds (self->timeout, fu_idle_check_cb, self); +} + +static void +fu_idle_stop (FuIdle *self) +{ + if (self->idle_id == 0) + return; + g_source_remove (self->idle_id); + self->idle_id = 0; +} + +void +fu_idle_reset (FuIdle *self) +{ + g_return_if_fail (FU_IS_IDLE (self)); + fu_idle_stop (self); + if (self->items->len == 0) + fu_idle_start (self); +} + +void +fu_idle_uninhibit (FuIdle *self, guint32 token) +{ + g_autoptr(FuMutexLocker) locker = fu_mutex_write_locker_new (self->items_mutex); + + g_return_if_fail (FU_IS_IDLE (self)); + g_return_if_fail (token != 0); + g_return_if_fail (locker != NULL); + + for (guint i = 0; i < self->items->len; i++) { + FuIdleItem *item = g_ptr_array_index (self->items, i); + if (item->token == token) { + g_debug ("uninhibiting: %s", item->reason); + g_ptr_array_remove_index (self->items, i); + break; + } + } + fu_idle_reset (self); +} + +guint32 +fu_idle_inhibit (FuIdle *self, const gchar *reason) +{ + FuIdleItem *item; + g_autoptr(FuMutexLocker) locker = fu_mutex_write_locker_new (self->items_mutex); + + g_return_val_if_fail (FU_IS_IDLE (self), 0); + g_return_val_if_fail (reason != NULL, 0); + g_return_val_if_fail (locker != NULL, 0); + + g_debug ("inhibiting: %s", reason); + item = g_new0 (FuIdleItem, 1); + item->reason = g_strdup (reason); + item->token = g_random_int_range (1, G_MAXINT); + g_ptr_array_add (self->items, item); + fu_idle_reset (self); + return item->token; +} + +void +fu_idle_set_timeout (FuIdle *self, guint timeout) +{ + g_return_if_fail (FU_IS_IDLE (self)); + g_debug ("setting timeout to %us", timeout); + self->timeout = timeout; + fu_idle_reset (self); +} + +static void +fu_idle_item_free (FuIdleItem *item) +{ + g_free (item->reason); + g_free (item); +} + +FuIdleLocker * +fu_idle_locker_new (FuIdle *self, const gchar *reason) +{ + FuIdleLocker *locker = g_new0 (FuIdleLocker, 1); + locker->idle = g_object_ref (self); + locker->token = fu_idle_inhibit (self, reason); + return locker; +} + +void +fu_idle_locker_free (FuIdleLocker *locker) +{ + if (locker == NULL) + return; + fu_idle_uninhibit (locker->idle, locker->token); + g_object_unref (locker->idle); + g_free (locker); +} + +static void +fu_idle_class_init (FuIdleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->finalize = fu_idle_finalize; + object_class->get_property = fu_idle_get_property; + object_class->set_property = fu_idle_set_property; + + pspec = g_param_spec_uint ("status", NULL, NULL, + FWUPD_STATUS_UNKNOWN, + FWUPD_STATUS_LAST, + FWUPD_STATUS_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_STATUS, pspec); +} + +static void +fu_idle_init (FuIdle *self) +{ + self->status = FWUPD_STATUS_IDLE; + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_idle_item_free); + self->items_mutex = fu_mutex_new (G_OBJECT_TYPE_NAME(self), "items"); +} + +static void +fu_idle_finalize (GObject *obj) +{ + FuIdle *self = FU_IDLE (obj); + + fu_idle_stop (self); + g_ptr_array_unref (self->items); + g_object_unref (self->items_mutex); + + G_OBJECT_CLASS (fu_idle_parent_class)->finalize (obj); +} + +FuIdle * +fu_idle_new (void) +{ + FuIdle *self; + self = g_object_new (FU_TYPE_IDLE, NULL); + return FU_IDLE (self); +} diff --git a/src/fu-idle.h b/src/fu-idle.h new file mode 100644 index 000000000..f5e4d0eb6 --- /dev/null +++ b/src/fu-idle.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_IDLE_H +#define __FU_IDLE_H + +G_BEGIN_DECLS + +#include +#include + +#include "fu-device.h" + +#define FU_TYPE_IDLE (fu_idle_get_type ()) +G_DECLARE_FINAL_TYPE (FuIdle, fu_idle, FU, IDLE, GObject) + +FuIdle *fu_idle_new (void); +guint32 fu_idle_inhibit (FuIdle *self, + const gchar *reason); +void fu_idle_uninhibit (FuIdle *self, + guint32 token); +void fu_idle_set_timeout (FuIdle *self, + guint timeout); +void fu_idle_reset (FuIdle *self); +FwupdStatus fu_idle_get_status (FuIdle *self); + +typedef struct { + FuIdle *idle; + guint32 token; +} FuIdleLocker; + +FuIdleLocker *fu_idle_locker_new (FuIdle *self, + const gchar *reason); +void fu_idle_locker_free (FuIdleLocker *locker); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuIdleLocker, fu_idle_locker_free) + +G_END_DECLS + +#endif /* __FU_IDLE_H */ + diff --git a/src/fu-main.c b/src/fu-main.c index b28ea9015..edf9567b9 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -182,6 +182,10 @@ fu_main_engine_status_changed_cb (FuEngine *engine, FuMainPrivate *priv) { fu_main_set_status (priv, status); + + /* engine has gone idle */ + if (status == FWUPD_STATUS_SHUTDOWN) + g_main_loop_quit (priv->loop); } static void @@ -674,6 +678,9 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, GVariant *val = NULL; g_autoptr(GError) error = NULL; + /* activity */ + fu_engine_idle_reset (priv->engine); + if (g_strcmp0 (method_name, "GetDevices") == 0) { g_autoptr(GPtrArray) devices = NULL; g_debug ("Called %s()", method_name); @@ -1102,6 +1109,9 @@ fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender, { FuMainPrivate *priv = (FuMainPrivate *) user_data; + /* activity */ + fu_engine_idle_reset (priv->engine); + if (g_strcmp0 (property_name, "DaemonVersion") == 0) return g_variant_new_string (VERSION); diff --git a/src/fu-plugin.c b/src/fu-plugin.c index ca965f1d9..58166fbda 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -60,6 +60,7 @@ enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_DEVICE_REGISTER, + SIGNAL_RULES_CHANGED, SIGNAL_RECOLDPLUG, SIGNAL_SET_COLDPLUG_DELAY, SIGNAL_CHECK_SUPPORTED, @@ -1557,6 +1558,7 @@ fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) { FuPluginPrivate *priv = fu_plugin_get_instance_private (self); g_ptr_array_add (priv->rules[rule], g_strdup (name)); + g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0); } /** @@ -1741,6 +1743,12 @@ fu_plugin_class_init (FuPluginClass *klass) G_STRUCT_OFFSET (FuPluginClass, check_supported), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, G_TYPE_STRING); + signals[SIGNAL_RULES_CHANGED] = + g_signal_new ("rules-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, rules_changed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void diff --git a/src/fu-plugin.h b/src/fu-plugin.h index 2764c65bd..3b3f042fe 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -45,8 +45,9 @@ struct _FuPluginClass FuDevice *device); gboolean (* check_supported) (FuPlugin *self, const gchar *guid); + void (* rules_changed) (FuPlugin *self); /*< private >*/ - gpointer padding[23]; + gpointer padding[22]; }; /** @@ -68,6 +69,7 @@ typedef enum { * @FU_PLUGIN_RULE_RUN_BEFORE: Order the plugin before another * @FU_PLUGIN_RULE_REQUIRES_QUIRK: Requires a specific quirk * @FU_PLUGIN_RULE_BETTER_THAN: Is better than another plugin + * @FU_PLUGIN_RULE_INHIBITS_IDLE: The plugin inhibits the idle shutdown * * The rules used for ordering plugins. * Plugins are expected to add rules in fu_plugin_initialize(). @@ -78,6 +80,7 @@ typedef enum { FU_PLUGIN_RULE_RUN_BEFORE, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_PLUGIN_RULE_BETTER_THAN, + FU_PLUGIN_RULE_INHIBITS_IDLE, /*< private >*/ FU_PLUGIN_RULE_LAST } FuPluginRule; diff --git a/src/meson.build b/src/meson.build index ed49f039d..4644c38ec 100644 --- a/src/meson.build +++ b/src/meson.build @@ -122,6 +122,7 @@ fwupdtool = executable( 'fu-device.c', 'fu-device-list.c', 'fu-device-locker.c', + 'fu-idle.c', 'fu-install-task.c', 'fu-keyring.c', 'fu-keyring-utils.c', @@ -202,6 +203,7 @@ executable( 'fu-device.c', 'fu-device-list.c', 'fu-device-locker.c', + 'fu-idle.c', 'fu-install-task.c', 'fu-keyring.c', 'fu-keyring-utils.c', @@ -271,6 +273,7 @@ if get_option('tests') 'fu-device-list.c', 'fu-device-locker.c', 'fu-history.c', + 'fu-idle.c', 'fu-install-task.c', 'fu-keyring.c', 'fu-keyring-result.c', From 328b00eec3f88d1959f1c26e1193820f10d7bb65 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 21 Nov 2018 11:09:45 +0000 Subject: [PATCH 092/254] Remove DaemonVersionFormat=quad This metadata key is now unnecessary, as firmwares are expected to set the version format in the metadata. If the metadata is missing, the LVFS allows a per-vendor default for non-semver release versions which is now unconditionally set in metadata. --- plugins/dell/dell.quirk | 7 ------- src/fu-engine.c | 16 ---------------- 2 files changed, 23 deletions(-) diff --git a/plugins/dell/dell.quirk b/plugins/dell/dell.quirk index d6c1c43f6..3a037e3a2 100644 --- a/plugins/dell/dell.quirk +++ b/plugins/dell/dell.quirk @@ -38,10 +38,3 @@ UefiVersionFormat = quad [SmbiosManufacturer=Alienware] UefiVersionFormat = quad - -# DEPRECATED: put this in the AppStream metadata itself using -# -# quad -# -[DaemonVersionFormat=quad] -ComponentIDs = com.dell.uefi*.firmware diff --git a/src/fu-engine.c b/src/fu-engine.c index 77bc05ab1..59b96da17 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -207,7 +207,6 @@ static gchar * fu_engine_get_release_version (FuEngine *self, XbNode *component, XbNode *rel) { FuVersionFormat fmt = FU_VERSION_FORMAT_TRIPLET; - const gchar *quirk; const gchar *version; const gchar *version_format; guint64 ver_uint32; @@ -221,21 +220,6 @@ fu_engine_get_release_version (FuEngine *self, XbNode *component, XbNode *rel) if (g_strstr_len (version, -1, ".") != NULL) return g_strdup (version); - /* fall back to the quirk database until all files have metadata */ - quirk = fu_quirks_lookup_by_id (self->quirks, - "DaemonVersionFormat=quad", - FU_QUIRKS_DAEMON_VERSION_FORMAT); - if (quirk != NULL) { - const gchar *id = xb_node_query_text (component, "id", NULL); - g_auto(GStrv) globs = g_strsplit (quirk, ",", -1); - for (guint i = 0; globs[i] != NULL; i++) { - if (fnmatch (globs[i], id, 0) == 0) { - fmt = FU_VERSION_FORMAT_QUAD; - break; - } - } - } - /* specified in metadata */ version_format = xb_node_query_text (component, "custom/value[@key='LVFS::VersionFormat']", From ec6190c4bf0237ed4a717f94b3583edac96aead5 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 25 Nov 2018 12:19:33 +0000 Subject: [PATCH 093/254] trivial: Fix regression when switching to indexed strings When we construct a local silo we need to build the index again. This fixes 'fwupdmgr get-details foo.cab' --- src/fu-engine.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 59b96da17..7904f21ab 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2217,6 +2217,14 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) return NULL; } + /* build the index */ + if (!xb_silo_query_build_index (silo, "component/provides/firmware", + "type", error)) + return FALSE; + if (!xb_silo_query_build_index (silo, "component/provides/firmware", + NULL, error)) + return FALSE; + /* does this exist in any enabled remote */ csum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); remote_id = fu_engine_get_remote_id_for_checksum (self, csum); From 1210332e0541a50b81f82a8f39b38cebbe461eb6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 26 Nov 2018 14:05:19 -0600 Subject: [PATCH 094/254] trivial: dell-dock: fail when EC indicates flashing an invalid/unsigned image Otherwise this would cause fwupd to sit in an endless loop when providing a bad image. This additional enum is only available in EC16, but since it doesn't break existing API on older EC images, don't bump minimum requirement to EC16 yet. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 00e8d6baf..4c6b506b7 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -40,6 +40,7 @@ typedef enum { FW_UPDATE_IN_PROGRESS, FW_UPDATE_COMPLETE, + FW_UPDATE_AUTHENTICATION_FAILED, } FuDellDockECFWUpdateStatus; const FuHIDI2CParameters ec_base_settings = { @@ -723,6 +724,13 @@ fu_dell_dock_ec_write_fw (FuDevice *device, GBytes *blob_fw, error_local->message, status); return TRUE; } + if (status == FW_UPDATE_AUTHENTICATION_FAILED) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid EC firmware image"); + return FALSE; + } } /* dock will reboot to re-read; this is to appease the daemon */ From 817a15a1bfa3e9a5399b9f11d5825c844f3671bd Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 26 Nov 2018 14:07:50 -0600 Subject: [PATCH 095/254] trivial: dell-dock: Set EC version to daemon before EC reset If the process fails (or was skipped due to 'skip-restart') this will prevent the daemon from trying again until the dock has been power cycled. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 4c6b506b7..893e8e017 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -688,6 +688,9 @@ fu_dell_dock_ec_write_fw (FuDevice *device, GBytes *blob_fw, if (!fu_dell_dock_hid_raise_mcu_clock (self->symbiote, FALSE, error)) return FALSE; + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + if (fu_device_has_custom_flag (device, "skip-restart")) { g_debug ("Skipping EC reset per quirk request"); return TRUE; @@ -733,9 +736,6 @@ fu_dell_dock_ec_write_fw (FuDevice *device, GBytes *blob_fw, } } - /* dock will reboot to re-read; this is to appease the daemon */ - fu_device_set_version (device, dynamic_version); - return TRUE; } From c0b20b119b7cb1bc493af0b502c7cb72c01967cf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 27 Nov 2018 14:51:56 +0000 Subject: [PATCH 096/254] Release fwupd 1.2.1 --- RELEASE | 11 ++--------- data/org.freedesktop.fwupd.metainfo.xml | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/RELEASE b/RELEASE index 6915bf67f..ea9f097a3 100644 --- a/RELEASE +++ b/RELEASE @@ -3,18 +3,11 @@ fwupd Release Notes Write release entries: git log --format="%s" --cherry-pick --right-only 1.2.0... | grep -i -v trivial | grep -v Merge | sort | uniq -Add any user visible changes into data/org.freedesktop.fwupd.metainfo.xml - -Version 1.2.1 -~~~~~~~~~~~~~ -Released: 2018-xx-xx - -New Features: -Bugfixes: +Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml +appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS Update translations: -appstream-util appdata-to-news data/org.freedesktop.fwupd.metainfo.xml > NEWS ninja-build fwupd-pot tx push --source tx pull --all --force --minimum-perc=5 diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index df7f45045..6052b4b12 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -31,6 +31,25 @@ moderate + + +

      This release adds the following features:

      +
        +
      • Add per-release install duration values
      • +
      • Shut down the daemon after 2h of inactivity when possible
      • +
      +

      This release fixes the following bugs:

      +
        +
      • Fix a use-after-free when using --immediate-exit
      • +
      • Fix flashing the 8bitdo SF30
      • +
      • Fix showing the custom remote agreements
      • +
      • Include the os-release information in the release metadata
      • +
      • Speed up startup by loading less thunderbolt firmware
      • +
      • Speed up startup by using a silo index for GUID queries
      • +
      • Use less memory and fragment the heap less when starting
      • +
      +
      +

      This release adds the following features:

      From 6a53116fb5c8d20263218b781af2f40e4070ac1b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 27 Nov 2018 14:53:43 +0000 Subject: [PATCH 097/254] trivial: post release version bump --- RELEASE | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE b/RELEASE index ea9f097a3..45c4eb558 100644 --- a/RELEASE +++ b/RELEASE @@ -2,7 +2,7 @@ fwupd Release Notes Write release entries: -git log --format="%s" --cherry-pick --right-only 1.2.0... | grep -i -v trivial | grep -v Merge | sort | uniq +git log --format="%s" --cherry-pick --right-only 1.2.1... | grep -i -v trivial | grep -v Merge | sort | uniq Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS @@ -19,7 +19,7 @@ git add ../po/*.po 2. Commit changes to git: # MAKE SURE THIS IS CORRECT -export release_ver="1.2.1" +export release_ver="1.2.2" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/meson.build b/meson.build index 16c76caa8..6a12c4b94 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.2.1', + version : '1.2.2', license : 'LGPL-2.1+', meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], From b97f07e7bef06616b583e8c088d48d11af05896c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 28 Nov 2018 10:13:15 +0000 Subject: [PATCH 098/254] Provide a way for plugins to decompress a custom archive to ram This allows plugins to load an archive supplied as the 'deliverable' of the cabinet archive. This means plugins can bundle up a set of images in a cross platform way, for instance adding boot.img+os.img+manifest.xml into a zip file, rather than having to (ab)use the DfuSe file format or deal with libarchive directly. --- src/fu-archive.c | 200 +++++++++++++++++++++++++++++++++++++++++++++ src/fu-archive.h | 32 ++++++++ src/fu-self-test.c | 60 ++++++++++++++ src/meson.build | 6 ++ 4 files changed, 298 insertions(+) create mode 100644 src/fu-archive.c create mode 100644 src/fu-archive.h diff --git a/src/fu-archive.c b/src/fu-archive.c new file mode 100644 index 000000000..4d5a0c599 --- /dev/null +++ b/src/fu-archive.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuArchive" + +#include "config.h" + +#include +#include +#include + +#include "fu-archive.h" + +/** + * SECTION:fu-archive + * @title: FuArchive + * @short_description: an in-memory archive decompressor + */ + +struct _FuArchive { + GObject parent_instance; + GHashTable *entries; +}; + +G_DEFINE_TYPE (FuArchive, fu_archive, G_TYPE_OBJECT) + +static void +fu_archive_finalize (GObject *obj) +{ + FuArchive *self = FU_ARCHIVE (obj); + + g_hash_table_unref (self->entries); + G_OBJECT_CLASS (fu_archive_parent_class)->finalize (obj); +} + +static void +fu_archive_class_init (FuArchiveClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_archive_finalize; +} + +static void +fu_archive_init (FuArchive *self) +{ + self->entries = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_bytes_unref); +} + +/** + * fu_archive_lookup_by_fn: + * @self: A #FuArchive + * @fn: A filename + * @error: A #GError, or %NULL + * + * Finds the blob referenced by filename + * + * Returns: (transfer none): a #GBytes, or %NULL if the filename was not found + **/ +GBytes * +fu_archive_lookup_by_fn (FuArchive *self, const gchar *fn, GError **error) +{ + GBytes *fw; + + g_return_val_if_fail (FU_IS_ARCHIVE (self), NULL); + g_return_val_if_fail (fn != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + fw = g_hash_table_lookup (self->entries, fn); + if (fw == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no blob for %s", fn); + } + return fw; +} + +/* workaround the struct types of libarchive */ +typedef struct archive _archive_read_ctx; + +static void +_archive_read_ctx_free (_archive_read_ctx *arch) +{ + archive_read_close (arch); + archive_read_free (arch); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(_archive_read_ctx, _archive_read_ctx_free) + +static gboolean +fu_archive_load (FuArchive *self, GBytes *blob, GError **error) +{ + int r; + g_autoptr(_archive_read_ctx) arch = NULL; + + /* decompress anything matching either glob */ + arch = archive_read_new (); + if (arch == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "libarchive startup failed"); + return FALSE; + } + archive_read_support_format_all (arch); + archive_read_support_filter_all (arch); + r = archive_read_open_memory (arch, + (void *) g_bytes_get_data (blob, NULL), + (size_t) g_bytes_get_size (blob)); + if (r != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot open: %s", + archive_error_string (arch)); + return FALSE; + } + while (TRUE) { + const gchar *fn; + gint64 bufsz; + gssize rc; + struct archive_entry *entry; + g_autofree guint8 *buf = NULL; + + r = archive_read_next_header (arch, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read header: %s", + archive_error_string (arch)); + return FALSE; + } + + /* only extract if valid */ + fn = archive_entry_pathname (entry); + if (fn == NULL) + continue; + bufsz = archive_entry_size (entry); + if (bufsz > 1024 * 1024 * 1024) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read huge files"); + return FALSE; + } + buf = g_malloc (bufsz); + rc = archive_read_data (arch, buf, (gsize) bufsz); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read data: %s", + archive_error_string (arch)); + return FALSE; + } + if (rc != bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "read %" G_GSSIZE_FORMAT " of %" G_GINT64_FORMAT, + rc, bufsz); + return FALSE; + } + g_debug ("adding %s [%" G_GINT64_FORMAT "]", fn, bufsz); + g_hash_table_insert (self->entries, + g_strdup (fn), + g_bytes_new_take (g_steal_pointer (&buf), bufsz)); + } + + /* success */ + return TRUE; +} + +/** + * fu_archive_new: + * @data: A #GBytes + * @flags: A #FuArchiveFlags, e.g. %FU_ARCHIVE_FLAG_NONE + * @error: A #GError, or %NULL + * + * Parses @data as an archive and decompresses all files to memory blobs. + * + * Returns: a #FuArchive, or %NULL if the archive was invalid in any way. + **/ +FuArchive * +fu_archive_new (GBytes *data, FuArchiveFlags flags, GError **error) +{ + g_autoptr(FuArchive) self = g_object_new (FU_TYPE_ARCHIVE, NULL); + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + if (!fu_archive_load (self, data, error)) + return NULL; + return g_steal_pointer (&self); +} diff --git a/src/fu-archive.h b/src/fu-archive.h new file mode 100644 index 000000000..c786de622 --- /dev/null +++ b/src/fu-archive.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_ARCHIVE_H +#define __FU_ARCHIVE_H + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_ARCHIVE (fu_archive_get_type ()) + +G_DECLARE_FINAL_TYPE (FuArchive, fu_archive, FU, ARCHIVE, GObject) + +typedef enum { + FU_ARCHIVE_FLAG_NONE = 0, + FU_ARCHIVE_FLAGS_LAST +} FuArchiveFlags; + +FuArchive *fu_archive_new (GBytes *data, + FuArchiveFlags flags, + GError **error); +GBytes *fu_archive_lookup_by_fn (FuArchive *self, + const gchar *fn, + GError **error); + +G_END_DECLS + +#endif /* __FU_ARCHIVE_H */ diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 75b21eb57..5b7fd5a36 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -15,6 +15,7 @@ #include #include +#include "fu-archive.h" #include "fu-common-cab.h" #include "fu-common-guid.h" #include "fu-common-version.h" @@ -52,6 +53,63 @@ fu_self_test_mkroot (void) g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); } +static void +fu_archive_invalid_func (void) +{ + g_autofree gchar *filename = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + + filename = fu_test_get_filename (TESTDATADIR, "metadata.xml"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + + archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_assert_null (archive); +} + +static void +fu_archive_cab_func (void) +{ + g_autofree gchar *checksum1 = NULL; + g_autofree gchar *checksum2 = NULL; + g_autofree gchar *filename = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + GBytes *data_tmp; + + filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + + archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_nonnull (archive); + + data_tmp = fu_archive_lookup_by_fn (archive, "firmware.metainfo.xml", &error); + g_assert_no_error (error); + g_assert_nonnull (data_tmp); + checksum1 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp); + g_assert_cmpstr (checksum1, ==, "8611114f51f7151f190de86a5c9259d79ff34216"); + + data_tmp = fu_archive_lookup_by_fn (archive, "firmware.bin", &error); + g_assert_no_error (error); + g_assert_nonnull (data_tmp); + checksum2 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp); + g_assert_cmpstr (checksum2, ==, "7c0ae84b191822bcadbdcbe2f74a011695d783c7"); + + data_tmp = fu_archive_lookup_by_fn (archive, "NOTGOINGTOEXIST.xml", &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert_null (data_tmp); +} + static void fu_common_version_guess_format_func (void) { @@ -3188,6 +3246,8 @@ main (int argc, char **argv) /* tests go here */ if (g_test_slow ()) g_test_add_func ("/fwupd/progressbar", fu_progressbar_func); + g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func); + g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func); g_test_add_func ("/fwupd/engine{requirements-other-device}", fu_engine_requirements_other_device_func); g_test_add_func ("/fwupd/device{incorporate}", fu_device_incorporate_func); g_test_add_func ("/fwupd/device{poll}", fu_device_poll_func); diff --git a/src/meson.build b/src/meson.build index 4644c38ec..6f7312544 100644 --- a/src/meson.build +++ b/src/meson.build @@ -25,6 +25,7 @@ endif libfwupdprivate = static_library( 'fwupdprivate', sources : [ + 'fu-archive.c', 'fu-common.c', 'fu-common-guid.c', 'fu-common-version.c', @@ -108,6 +109,7 @@ fwupdtool = executable( sources : [ 'fu-tool.c', keyring_src, + 'fu-archive.c', 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', @@ -188,6 +190,7 @@ executable( resources_src, sources : [ keyring_src, + 'fu-archive.c', 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', @@ -259,6 +262,7 @@ if get_option('tests') sources : [ keyring_src, 'fu-self-test.c', + 'fu-archive.c', 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', @@ -324,6 +328,8 @@ if get_option('introspection') gir_dep = declare_dependency(sources: gir) gnome.generate_gir(fwupd, sources : [ + 'fu-archive.c', + 'fu-archive.h', 'fu-chunk.c', 'fu-chunk.h', 'fu-common.c', From 43fb4a71106f4643215affea499b32c629f4fa4d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 28 Nov 2018 13:41:54 +0000 Subject: [PATCH 099/254] trivial: Update two release note typos --- data/org.freedesktop.fwupd.metainfo.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 6052b4b12..ec990b185 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -138,7 +138,7 @@
    2. Allow different plugins to add the same device
    3. Allow flashing unifying devices in recovery mode
    4. Allow running synapticsmst on non-Dell hardware
    5. -
    6. Check the ESP for sanity at at startup
    7. +
    8. Check the ESP for sanity at startup
    9. Do not hold hidraw devices open forever
    10. Don't override _FORTIFY_SOURCE when building the EFI binary
    11. Don't show passwords in fwupdmgr
    12. @@ -191,7 +191,7 @@

      This release adds the following features:

        -
      • Add an plugin to update some future Wacom tablets
      • +
      • Add a plugin to update some future Wacom tablets
      • Add 'fwupdmgr get-topology' to show logical device tree
      • Add support for creating a flatpak
      • Add support for creating a snap
      • From 847a6b11b2cef720838b3ed86ee76c4d5ea0cc29 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 28 Nov 2018 13:42:21 +0000 Subject: [PATCH 100/254] trivial: Don't ask translators to translate the release notes --- po/POTFILES.in | 1 - po/POTFILES.skip | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 po/POTFILES.skip diff --git a/po/POTFILES.in b/po/POTFILES.in index 5fcb39037..701065707 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,4 +1,3 @@ -data/org.freedesktop.fwupd.metainfo.xml data/remotes.d/lvfs.metainfo.xml data/remotes.d/lvfs-testing.metainfo.xml policy/org.freedesktop.fwupd.policy.in diff --git a/po/POTFILES.skip b/po/POTFILES.skip new file mode 100644 index 000000000..aff3fbe05 --- /dev/null +++ b/po/POTFILES.skip @@ -0,0 +1 @@ +data/org.freedesktop.fwupd.metainfo.xml From 596f93f50bc874154ea2e235745d1ff67577b756 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 28 Nov 2018 15:01:05 +0000 Subject: [PATCH 101/254] trivial: Allow calling fu_device_has_guid() with non-GUID text This matches the behaviour of fu_device_add_guid(). --- src/fu-device.c | 24 ++++++++++++++++++++++++ src/fu-device.h | 3 ++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/fu-device.c b/src/fu-device.c index 3fd374213..5059c0b7c 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -770,6 +770,30 @@ fu_device_add_guid_safe (FuDevice *self, const gchar *guid) fu_device_add_guid_quirks (self, guid); } +/** + * fu_device_has_guid: + * @self: A #FuDevice + * @guid: A GUID, e.g. `WacomAES` + * + * Finds out if the device has a specific GUID. + * + * Returns: %TRUE if the GUID is found + * + * Since: 1.2.2 + **/ +gboolean +fu_device_has_guid (FuDevice *self, const gchar *guid) +{ + /* make valid */ + if (!fu_common_guid_is_valid (guid)) { + g_autofree gchar *tmp = fu_common_guid_from_string (guid); + return fwupd_device_has_guid (FWUPD_DEVICE (self), tmp); + } + + /* already valid */ + return fwupd_device_has_guid (FWUPD_DEVICE (self), guid); +} + /** * fu_device_add_guid: * @self: A #FuDevice diff --git a/src/fu-device.h b/src/fu-device.h index 9fe7b018e..27461f91a 100644 --- a/src/fu-device.h +++ b/src/fu-device.h @@ -85,7 +85,6 @@ FuDevice *fu_device_new (void); #define fu_device_set_created(d,v) fwupd_device_set_created(FWUPD_DEVICE(d),v) #define fu_device_set_description(d,v) fwupd_device_set_description(FWUPD_DEVICE(d),v) #define fu_device_set_flags(d,v) fwupd_device_set_flags(FWUPD_DEVICE(d),v) -#define fu_device_has_guid(d,v) fwupd_device_has_guid(FWUPD_DEVICE(d),v) #define fu_device_set_modified(d,v) fwupd_device_set_modified(FWUPD_DEVICE(d),v) #define fu_device_set_plugin(d,v) fwupd_device_set_plugin(FWUPD_DEVICE(d),v) #define fu_device_set_serial(d,v) fwupd_device_set_serial(FWUPD_DEVICE(d),v) @@ -130,6 +129,8 @@ void fu_device_set_equivalent_id (FuDevice *self, const gchar *equivalent_id); void fu_device_add_guid (FuDevice *self, const gchar *guid); +gboolean fu_device_has_guid (FuDevice *self, + const gchar *guid); gchar *fu_device_get_guids_as_str (FuDevice *self); FuDevice *fu_device_get_alternate (FuDevice *self); FuDevice *fu_device_get_parent (FuDevice *self); From 57908bebc19d239612b8b53d9d80687b9d7288fa Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 29 Nov 2018 11:59:15 +0000 Subject: [PATCH 102/254] wacomhid: Rename to wacom-usb We're adding another Wacom plugin soon, this one also using hidraw -- but the new protocol uses a different 'raw' protocol and does not use USB. --- contrib/fwupd.spec.in | 2 +- plugins/meson.build | 2 +- plugins/{wacomhid => wacom-usb}/README.md | 2 +- .../fu-plugin-wacom-usb.c} | 0 .../{wacomhid => wacom-usb}/fu-self-test.c | 0 .../{wacomhid => wacom-usb}/fu-wac-common.c | 0 .../{wacomhid => wacom-usb}/fu-wac-common.h | 0 .../{wacomhid => wacom-usb}/fu-wac-device.c | 0 .../{wacomhid => wacom-usb}/fu-wac-device.h | 0 .../{wacomhid => wacom-usb}/fu-wac-firmware.c | 0 .../{wacomhid => wacom-usb}/fu-wac-firmware.h | 0 .../fu-wac-module-bluetooth.c | 0 .../fu-wac-module-bluetooth.h | 0 .../fu-wac-module-touch.c | 0 .../fu-wac-module-touch.h | 0 .../{wacomhid => wacom-usb}/fu-wac-module.c | 0 .../{wacomhid => wacom-usb}/fu-wac-module.h | 0 plugins/{wacomhid => wacom-usb}/meson.build | 12 +++--- .../wacom-usb.quirk} | 40 +++++++++---------- 19 files changed, 29 insertions(+), 29 deletions(-) rename plugins/{wacomhid => wacom-usb}/README.md (98%) rename plugins/{wacomhid/fu-plugin-wacomhid.c => wacom-usb/fu-plugin-wacom-usb.c} (100%) rename plugins/{wacomhid => wacom-usb}/fu-self-test.c (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-common.c (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-common.h (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-device.c (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-device.h (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-firmware.c (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-firmware.h (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-module-bluetooth.c (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-module-bluetooth.h (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-module-touch.c (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-module-touch.h (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-module.c (100%) rename plugins/{wacomhid => wacom-usb}/fu-wac-module.h (100%) rename plugins/{wacomhid => wacom-usb}/meson.build (85%) rename plugins/{wacomhid/wacomhid.quirk => wacom-usb/wacom-usb.quirk} (84%) diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index dfc036acc..ccf765093 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -291,7 +291,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_unifying.so %{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so -%{_libdir}/fwupd-plugins-3/libfu_plugin_wacomhid.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_usb.so %ghost %{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_uefi} %{_datadir}/locale/*/LC_IMAGES/fwupd* diff --git a/plugins/meson.build b/plugins/meson.build index e62f82c5e..4408d2f4c 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -11,7 +11,7 @@ subdir('test') subdir('udev') subdir('unifying') subdir('upower') -subdir('wacomhid') +subdir('wacom-usb') subdir('superio') # depends on dfu diff --git a/plugins/wacomhid/README.md b/plugins/wacom-usb/README.md similarity index 98% rename from plugins/wacomhid/README.md rename to plugins/wacom-usb/README.md index 8e01ec53b..d5178bb1b 100644 --- a/plugins/wacomhid/README.md +++ b/plugins/wacom-usb/README.md @@ -1,4 +1,4 @@ -Wacom HID Support +Wacom USB Support ================= Introduction diff --git a/plugins/wacomhid/fu-plugin-wacomhid.c b/plugins/wacom-usb/fu-plugin-wacom-usb.c similarity index 100% rename from plugins/wacomhid/fu-plugin-wacomhid.c rename to plugins/wacom-usb/fu-plugin-wacom-usb.c diff --git a/plugins/wacomhid/fu-self-test.c b/plugins/wacom-usb/fu-self-test.c similarity index 100% rename from plugins/wacomhid/fu-self-test.c rename to plugins/wacom-usb/fu-self-test.c diff --git a/plugins/wacomhid/fu-wac-common.c b/plugins/wacom-usb/fu-wac-common.c similarity index 100% rename from plugins/wacomhid/fu-wac-common.c rename to plugins/wacom-usb/fu-wac-common.c diff --git a/plugins/wacomhid/fu-wac-common.h b/plugins/wacom-usb/fu-wac-common.h similarity index 100% rename from plugins/wacomhid/fu-wac-common.h rename to plugins/wacom-usb/fu-wac-common.h diff --git a/plugins/wacomhid/fu-wac-device.c b/plugins/wacom-usb/fu-wac-device.c similarity index 100% rename from plugins/wacomhid/fu-wac-device.c rename to plugins/wacom-usb/fu-wac-device.c diff --git a/plugins/wacomhid/fu-wac-device.h b/plugins/wacom-usb/fu-wac-device.h similarity index 100% rename from plugins/wacomhid/fu-wac-device.h rename to plugins/wacom-usb/fu-wac-device.h diff --git a/plugins/wacomhid/fu-wac-firmware.c b/plugins/wacom-usb/fu-wac-firmware.c similarity index 100% rename from plugins/wacomhid/fu-wac-firmware.c rename to plugins/wacom-usb/fu-wac-firmware.c diff --git a/plugins/wacomhid/fu-wac-firmware.h b/plugins/wacom-usb/fu-wac-firmware.h similarity index 100% rename from plugins/wacomhid/fu-wac-firmware.h rename to plugins/wacom-usb/fu-wac-firmware.h diff --git a/plugins/wacomhid/fu-wac-module-bluetooth.c b/plugins/wacom-usb/fu-wac-module-bluetooth.c similarity index 100% rename from plugins/wacomhid/fu-wac-module-bluetooth.c rename to plugins/wacom-usb/fu-wac-module-bluetooth.c diff --git a/plugins/wacomhid/fu-wac-module-bluetooth.h b/plugins/wacom-usb/fu-wac-module-bluetooth.h similarity index 100% rename from plugins/wacomhid/fu-wac-module-bluetooth.h rename to plugins/wacom-usb/fu-wac-module-bluetooth.h diff --git a/plugins/wacomhid/fu-wac-module-touch.c b/plugins/wacom-usb/fu-wac-module-touch.c similarity index 100% rename from plugins/wacomhid/fu-wac-module-touch.c rename to plugins/wacom-usb/fu-wac-module-touch.c diff --git a/plugins/wacomhid/fu-wac-module-touch.h b/plugins/wacom-usb/fu-wac-module-touch.h similarity index 100% rename from plugins/wacomhid/fu-wac-module-touch.h rename to plugins/wacom-usb/fu-wac-module-touch.h diff --git a/plugins/wacomhid/fu-wac-module.c b/plugins/wacom-usb/fu-wac-module.c similarity index 100% rename from plugins/wacomhid/fu-wac-module.c rename to plugins/wacom-usb/fu-wac-module.c diff --git a/plugins/wacomhid/fu-wac-module.h b/plugins/wacom-usb/fu-wac-module.h similarity index 100% rename from plugins/wacomhid/fu-wac-module.h rename to plugins/wacom-usb/fu-wac-module.h diff --git a/plugins/wacomhid/meson.build b/plugins/wacom-usb/meson.build similarity index 85% rename from plugins/wacomhid/meson.build rename to plugins/wacom-usb/meson.build index cd655bffa..f7f74648d 100644 --- a/plugins/wacomhid/meson.build +++ b/plugins/wacom-usb/meson.build @@ -1,10 +1,10 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginWac"'] +cargs = ['-DG_LOG_DOMAIN="FuPluginWacomUsb"'] -install_data(['wacomhid.quirk'], +install_data(['wacom-usb.quirk'], install_dir: join_paths(datadir, 'fwupd', 'quirks.d') ) -shared_module('fu_plugin_wacomhid', +shared_module('fu_plugin_wacom_usb', sources : [ 'fu-wac-common.c', 'fu-wac-device.c', @@ -12,7 +12,7 @@ shared_module('fu_plugin_wacomhid', 'fu-wac-module.c', 'fu-wac-module-bluetooth.c', 'fu-wac-module-touch.c', - 'fu-plugin-wacomhid.c', + 'fu-plugin-wacom-usb.c', ], include_directories : [ include_directories('../..'), @@ -35,7 +35,7 @@ if get_option('tests') testdatadir = join_paths(meson.current_source_dir(), 'tests') cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( - 'wacomhid-self-test', + 'wacom-usb-self-test', sources : [ 'fu-self-test.c', 'fu-wac-common.c', @@ -62,5 +62,5 @@ if get_option('tests') ], c_args : cargs ) - test('wacomhid-self-test', e) + test('wacom-usb-self-test', e) endif diff --git a/plugins/wacomhid/wacomhid.quirk b/plugins/wacom-usb/wacom-usb.quirk similarity index 84% rename from plugins/wacomhid/wacomhid.quirk rename to plugins/wacom-usb/wacom-usb.quirk index 643524232..8f937b313 100644 --- a/plugins/wacomhid/wacomhid.quirk +++ b/plugins/wacom-usb/wacom-usb.quirk @@ -1,99 +1,99 @@ # MobileStudio Pro 13 (touch) [DTH-W1320] [DeviceInstanceId=USB\VID_056A&PID_034A] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # MobileStudio Pro 16 (touch) [DTH-W1620] [DeviceInstanceId=USB\VID_056A&PID_034B] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # MobileStudio Pro 13 (pen/pad) [DTH-W1320] [DeviceInstanceId=USB\VID_056A&PID_034D] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # MobileStudio Pro 16 (pen/pad) [DTH-W1620] [DeviceInstanceId=USB\VID_056A&PID_034E] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos Pro medium (2nd-gen BT) [PTH-660] [DeviceInstanceId=USB\VID_056A&PID_0360] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos Pro large (2nd-gen BT) [PTH-860] [DeviceInstanceId=USB\VID_056A&PID_0361] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos BT S (3rd-gen BT) [CTL-4100WL] [DeviceInstanceId=USB\VID_056A&PID_0377] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos BT M (3rd-gen BT) [CTL-6100WL] [DeviceInstanceId=USB\VID_056A&PID_0379] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Cintiq Pro 13 (pen/pad) [DTH-1320] [DeviceInstanceId=USB\VID_056A&PID_034F] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Cintiq Pro 16 (pen/pad) [DTH-1620] [DeviceInstanceId=USB\VID_056A&PID_0350] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Cintiq Pro 13 (touch) [DTH-1320] [DeviceInstanceId=USB\VID_056A&PID_0353] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Cintiq Pro 16 (touch) [DTH-1620] [DeviceInstanceId=USB\VID_056A&PID_0354] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos Pro medium (2nd-gen USB) [PTH-660] [DeviceInstanceId=USB\VID_056A&PID_0357] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos Pro large (2nd-gen USB) [PTH-860] [DeviceInstanceId=USB\VID_056A&PID_0358] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Pen [DTH-1152] [DeviceInstanceId=USB\VID_056A&PID_035A] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Touch [DTH-1152] [DeviceInstanceId=USB\VID_056A&PID_0368] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos S 3rd-gen (USB) [CTL-4100] [DeviceInstanceId=USB\VID_056A&PID_0374] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos M 3rd-gen (USB) [NA] [DeviceInstanceId=USB\VID_056A&PID_0375] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos BT S 3rd-gen (USB) [CTL-4100WL] [DeviceInstanceId=USB\VID_056A&PID_0376] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version # Intuos BT M 3rd-gen (USB) [CTL-6100WL] [DeviceInstanceId=USB\VID_056A&PID_0378] -Plugin = wacomhid +Plugin = wacom-usb Flags = use-runtime-version From 74f976a821fa87e8ed49a45b935f9ed100c70c05 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 29 Nov 2018 11:08:05 +0000 Subject: [PATCH 103/254] Add more standard USB identifier GUIDs These are specified in: https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers --- src/fu-usb-device.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/fu-usb-device.c b/src/fu-usb-device.c index 127d49429..996ef4459 100644 --- a/src/fu-usb-device.c +++ b/src/fu-usb-device.c @@ -228,6 +228,7 @@ fu_usb_device_probe (FuDevice *device, GError **error) g_autofree gchar *devid1 = NULL; g_autofree gchar *devid2 = NULL; g_autofree gchar *vendor_id = NULL; + g_autoptr(GPtrArray) intfs = NULL; /* set vendor ID */ vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); @@ -255,6 +256,29 @@ fu_usb_device_probe (FuDevice *device, GError **error) g_usb_device_get_vid (priv->usb_device)); fu_device_add_guid (device, devid0); + /* add the interface GUIDs */ + intfs = g_usb_device_get_interfaces (priv->usb_device, error); + if (intfs == NULL) + return FALSE; + for (guint i = 0; i < intfs->len; i++) { + GUsbInterface *intf = g_ptr_array_index (intfs, i); + g_autofree gchar *intid1 = NULL; + g_autofree gchar *intid2 = NULL; + g_autofree gchar *intid3 = NULL; + intid1 = g_strdup_printf ("USB\\CLASS_%02X&SUBCLASS_%02X&PROT_%02X", + g_usb_interface_get_class (intf), + g_usb_interface_get_subclass (intf), + g_usb_interface_get_protocol (intf)); + fu_device_add_guid (device, intid1); + intid2 = g_strdup_printf ("USB\\CLASS_%02X&SUBCLASS_%02X", + g_usb_interface_get_class (intf), + g_usb_interface_get_subclass (intf)); + fu_device_add_guid (device, intid2); + intid3 = g_strdup_printf ("USB\\CLASS_%02X", + g_usb_interface_get_class (intf)); + fu_device_add_guid (device, intid3); + } + /* subclassed */ if (klass->probe != NULL) { if (!klass->probe (self, error)) From 15e4b0caaf6fac7061883378249c368bddb65888 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 28 Nov 2018 12:44:12 -0600 Subject: [PATCH 104/254] installed-tests: Adjust to actually use a remote for installed tests By using a remote, this should allow using gnome-software to do the installed tests without hacking around much. Fixes: https://github.com/hughsie/fwupd/issues/862 Fixes: https://github.com/hughsie/fwupd/issues/809 --- contrib/debian/fwupd-tests.install | 1 + contrib/debian/fwupd-tests.postinst | 8 ++ contrib/debian/rules | 1 + contrib/fwupd.spec.in | 5 +- data/installed-tests/README.md | 78 ++++++++++++++++++ data/installed-tests/firmware-example.xml.gz | Bin 1361 -> 0 bytes .../firmware-example.xml.gz.asc | 11 --- data/installed-tests/fwupd-tests.xml | 77 +++++++++++++++++ data/installed-tests/fwupdmgr.sh | 4 +- data/installed-tests/meson.build | 12 ++- data/installed-tests/remote.conf.in | 9 ++ 11 files changed, 189 insertions(+), 17 deletions(-) create mode 100644 data/installed-tests/README.md delete mode 100644 data/installed-tests/firmware-example.xml.gz delete mode 100644 data/installed-tests/firmware-example.xml.gz.asc create mode 100644 data/installed-tests/fwupd-tests.xml create mode 100644 data/installed-tests/remote.conf.in diff --git a/contrib/debian/fwupd-tests.install b/contrib/debian/fwupd-tests.install index 481df00f2..9002c417e 100644 --- a/contrib/debian/fwupd-tests.install +++ b/contrib/debian/fwupd-tests.install @@ -5,3 +5,4 @@ usr/share/installed-tests/* usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so debian/lintian/fwupd-tests usr/share/lintian/overrides +etc/fwupd/remotes.d/fwupd-tests.conf diff --git a/contrib/debian/fwupd-tests.postinst b/contrib/debian/fwupd-tests.postinst index a3def5ecd..096c50f21 100644 --- a/contrib/debian/fwupd-tests.postinst +++ b/contrib/debian/fwupd-tests.postinst @@ -12,4 +12,12 @@ if [ "$1" = configure ] && [ -z "$2" ]; then echo "To enable test suite, modify /etc/fwupd/daemon.conf" fi fi + if [ -f /etc/fwupd/remotes.d/fwupd-tests.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + else + echo "To enable test suite, enable fwupd-tests remote" + fi + + fi fi diff --git a/contrib/debian/rules b/contrib/debian/rules index 666cc6e34..a1ec4bdaa 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -62,6 +62,7 @@ override_dh_install: #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so + rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf ifeq (debian,$(SB_STYLE)) # Generate the template source for the Debian signing service to use diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index ccf765093..28a55bc43 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -307,12 +307,13 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %files tests %dir %{_datadir}/installed-tests/fwupd -%{_datadir}/installed-tests/fwupd/firmware-example.xml.gz -%{_datadir}/installed-tests/fwupd/firmware-example.xml.gz.asc +%{_datadir}/installed-tests/fwupd/fwupd-tests.xml %{_datadir}/installed-tests/fwupd/*.test %{_datadir}/installed-tests/fwupd/*.cab %{_datadir}/installed-tests/fwupd/*.sh %{_datadir}/installed-tests/fwupd/*.py* +%dir %{_sysconfdir}/fwupd/remotes.d +%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd-tests.conf %changelog * #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG# diff --git a/data/installed-tests/README.md b/data/installed-tests/README.md new file mode 100644 index 000000000..d48d38dd6 --- /dev/null +++ b/data/installed-tests/README.md @@ -0,0 +1,78 @@ +Installed tests +========= + +A test suite that can be used to interact with a fake device is installed when +configured with `-Ddaemon=true` and `-Dtests=true`. + +By default this test suite is disabled. + +Enabling +======= +To enable the test suite: +1. Modify `/etc/fwupd/daemon.conf` to remove the `test` plugin from `BlacklistPlugins` + ``` + # sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + ``` +2. Enable the `fwupd-tests` remote for local CAB files. + ``` + # fwupdmgr enable-remote fwupd-tests + ``` + +Using test suite +===== +When the daemon is started with the test suite enabled a fake webcam device will be created with a pending update. + +``` +Integrated Webcam™ + DeviceId: 08d460be0f1f9f128413f816022a6439e0078018 + Guid: b585990a-003e-5270-89d5-3705a17f9a43 + Summary: A fake webcam + Plugin: test + Flags: updatable|supported|registered + Vendor: ACME Corp. + VendorId: USB:0x046D + Version: 1.2.2 + VersionLowest: 1.2.0 + VersionBootloader: 0.1.2 + Icon: preferences-desktop-keyboard + Created: 2018-11-29 +``` + +## Upgrading +This can be upgraded to a firmware version `1.2.4` by using `fwupdmgr update` or any fwupd frontend. + +``` +$ fwupdmgr get-updates +Integrated Webcam™ has firmware updates: +GUID: b585990a-003e-5270-89d5-3705a17f9a43 +ID: fakedevice.firmware +Update Version: 1.2.4 +Update Name: FakeDevice Firmware +Update Summary: Firmware for the ACME Corp Integrated Webcam +Update Remote ID: fwupd-tests +Update Checksum: SHA1(fc0aabcf98bf3546c91270f2941f0acd0395dd79) +Update Location: ./fakedevice124.cab +Update Description: Fixes another bug with the flux capacitor to prevent time going backwards. + +$ fwupdmgr update +Decompressing… [***************************************] +Authenticating… [***************************************] +Updating Integrated Webcam™… ] +Verifying… [***************************************] Less than one minute remaining… +``` + +## Downgrading +It can also be downgraded to firmware version `1.2.3`. +``` +$ fwupdmgr downgrade +Choose a device: +0. Cancel +1. 08d460be0f1f9f128413f816022a6439e0078018 (Integrated Webcam™) +2. 8a21cacfb0a8d2b30c5ee9290eb71db021619f8b (XPS 13 9370 System Firmware) +3. d10c5f0ed12c6dc773f596b8ac51f8ace4355380 (XPS 13 9370 Thunderbolt Controller) +1 +Decompressing… [***************************************] +Authenticating… [***************************************] +Downgrading Integrated Webcam™… \ ] +Verifying… [***************************************] Less than one minute remaining… +``` diff --git a/data/installed-tests/firmware-example.xml.gz b/data/installed-tests/firmware-example.xml.gz deleted file mode 100644 index f2d02082c1c978c9552ae6bd346f3606a8576d8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1361 zcmV-X1+MxZiwFq4tU_4=|7K}&ZFgaEWi4W1VlgpdHDP8nV_{)sV>dNoFk?3{HDWL} zH#jk2Gd5y5Gh{JlFf%TAZEOJLS6OcxHxPc$uORldSc&J7EMx^iS~mq!pgT6Er6@1s zJh=;qa9IYJ9Hg@;e%~oHu7>$Js{FK7A?MdBTggtTU)QzkuI2|JNo_}lC6HIIfBTud zZo3uvwHaX1xd9^i6MS&>YDwn%{nT_~OkYn0|p1VmmaVuG( zE<`GPgUypy5V1uNkAFaFQA7xz|ctkLMATmfTta=@!<+L(u$q5BH+k z2N48Ml7}QjLL9jWg-q5WoHbW0MZ>9y;xT9zC!kqdYeMAMLYx6DjOUUuCKRw_X{0Vn zQA9211JHaQj@@NjMsfwNBOIHBAj5a5YBwii_0gkTX}%)o=Jb$`?jo0ydHdud4CN1*+%~1C>}obG3$xG!;^+v z${xv+g)s6&syO;l)YAjU)?-&ZLQ;{oA<=iBTb z!kSOv>t6npmU>WudM1LCP9#=X9LYWu28S@xnm0*%Tb#_FdxV}qorN++F(?w(K}Mq^ zFdJe~c&mNEDBcYyB%t;b>U_5>dvX9=+Vbdr-1oN|rvn6kGxn2f2y`9Nz-9@}R;h!! z9f17t<`pALWIVEQW6L0ZNspGEfnRY{aj$^p+7&XF+PK^^&vOux%H(_zU3?aPy_a4e z$FAQexqc7aI^IExyWEQR5n=RAZpCZD(-JG*;^mV(sT}iGdNDpnEVs!gt(0QkIHBA~;yL_AZgWgvE-qpRdsx)dUeg5o&z#s7#_B^AO1@Hq~$BA4JGcM< + + + fakedevice.firmware + FakeDevice Firmware + Firmware for the ACME Corp Integrated Webcam + ACME Corp + GPL-2.0+ +

        Updating the firmware on your webcam device improves performance and adds new features.

        + http://www.acme.com/ + + + 17 + 1163 + ./fakedevice124.cab + fc0aabcf98bf3546c91270f2941f0acd0395dd79 + 2b8546ba805ad10bf8a2e5ad539d53f303812ba5 +

        Fixes another bug with the flux capacitor to prevent time going backwards.

        +
        + + 17 + 1153 + ./fakedevice123.cab + bc3c32f42cf33fe5aade64f999417251fd8208d3 + 7998cd212721e068b2411135e1f90d0ad436d730 +

        Fixes a bug with the flux capacitor to avoid year 2038 overflow.

        +
        +
        + + b585990a-003e-5270-89d5-3705a17f9a43 + +
        + + com.hughski.ColorHug2.firmware + ColorHug2 + Firmware for the Hughski ColorHug2 Colorimeter + Hughski Limited + GPL-2.0+ +

        Updating the firmware on your ColorHug2 device improves performance and adds new features.

        + http://www.hughski.com/ + + + 16384 + 19592 + hughski-colorhug2-2.0.7.cab + 490be5c0b13ca4a3f169bf8bc682ba127b8f7b96 + 658851e6f27c4d87de19cd66b97b610d100efe09 +

        This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

        +
        +
        + + 2082b5e0-7a64-478a-b1b2-e3404fab6dad + +
        + + com.hughski.ColorHug.firmware + ColorHug + Firmware for the Hughski ColorHug Colorimeter + Hughski Limited + GPL-2.0+ +

        Updating the firmware on your ColorHug device improves performance and adds new features.

        + http://www.hughski.com/ + + + 16384 + 18054 + hughski-colorhug-1.2.6.cab + 570a4259af0c7670f3883e84d2f4e6ff7de572c2 + 111784ffadfd5dd43f05655b266b5142230195b6 +

        This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

        +
        +
        + + 40338ceb-b966-4eae-adae-9c32edfcc484 + +
        +
        diff --git a/data/installed-tests/fwupdmgr.sh b/data/installed-tests/fwupdmgr.sh index 1df2efb49..e4ff45265 100755 --- a/data/installed-tests/fwupdmgr.sh +++ b/data/installed-tests/fwupdmgr.sh @@ -9,8 +9,8 @@ fwupdmgr get-remotes rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi # --- -echo "Refreshing with dummy metadata..." -fwupdmgr refresh ${dirname}/firmware-example.xml.gz ${dirname}/firmware-example.xml.gz.asc lvfs +echo "Enabling fwupd-tests remote..." +fwupdmgr enable-remote fwupd-tests rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi # --- diff --git a/data/installed-tests/meson.build b/data/installed-tests/meson.build index 4e38f95a5..eb33fa9f5 100644 --- a/data/installed-tests/meson.build +++ b/data/installed-tests/meson.build @@ -13,8 +13,7 @@ configure_file( install_data([ 'fwupdmgr.sh', - 'firmware-example.xml.gz', - 'firmware-example.xml.gz.asc', + 'fwupd-tests.xml', 'hardware.py', ], install_dir : 'share/installed-tests/fwupd', @@ -46,3 +45,12 @@ custom_target('installed-cab124', install: true, install_dir: join_paths('share', 'installed-tests', 'fwupd'), ) + +# replace @installedtestsdir@ +configure_file( + input : 'remote.conf.in', + output : 'fwupd-tests.conf', + configuration : con2, + install: true, + install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), +) diff --git a/data/installed-tests/remote.conf.in b/data/installed-tests/remote.conf.in new file mode 100644 index 000000000..dca038b37 --- /dev/null +++ b/data/installed-tests/remote.conf.in @@ -0,0 +1,9 @@ +[fwupd Remote] +# This is a local fwupd remote that is used only for installed tests +# either from continuous integration or for fake devices from fwupd +# frontends + +Enabled=false +Title=fwupd test suite +Keyring=none +MetadataURI=file://@installedtestsdir@/fwupd-tests.xml From 1d9c2ec1f1c667c7cb8079b23a0d92ad002ff640 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Nov 2018 10:27:50 +0000 Subject: [PATCH 105/254] trivial: Allow loading archives ignoring the path --- src/fu-archive.c | 14 ++++++++++---- src/fu-archive.h | 11 ++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/fu-archive.c b/src/fu-archive.c index 4d5a0c599..c12d0b3cc 100644 --- a/src/fu-archive.c +++ b/src/fu-archive.c @@ -92,7 +92,7 @@ _archive_read_ctx_free (_archive_read_ctx *arch) G_DEFINE_AUTOPTR_CLEANUP_FUNC(_archive_read_ctx, _archive_read_ctx_free) static gboolean -fu_archive_load (FuArchive *self, GBytes *blob, GError **error) +fu_archive_load (FuArchive *self, GBytes *blob, FuArchiveFlags flags, GError **error) { int r; g_autoptr(_archive_read_ctx) arch = NULL; @@ -124,6 +124,7 @@ fu_archive_load (FuArchive *self, GBytes *blob, GError **error) gint64 bufsz; gssize rc; struct archive_entry *entry; + g_autofree gchar *fn_key = NULL; g_autofree guint8 *buf = NULL; r = archive_read_next_header (arch, &entry); @@ -168,9 +169,14 @@ fu_archive_load (FuArchive *self, GBytes *blob, GError **error) rc, bufsz); return FALSE; } - g_debug ("adding %s [%" G_GINT64_FORMAT "]", fn, bufsz); + if (flags & FU_ARCHIVE_FLAG_IGNORE_PATH) { + fn_key = g_path_get_basename (fn); + } else { + fn_key = g_strdup (fn); + } + g_debug ("adding %s [%" G_GINT64_FORMAT "]", fn_key, bufsz); g_hash_table_insert (self->entries, - g_strdup (fn), + g_steal_pointer (&fn_key), g_bytes_new_take (g_steal_pointer (&buf), bufsz)); } @@ -194,7 +200,7 @@ fu_archive_new (GBytes *data, FuArchiveFlags flags, GError **error) g_autoptr(FuArchive) self = g_object_new (FU_TYPE_ARCHIVE, NULL); g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - if (!fu_archive_load (self, data, error)) + if (!fu_archive_load (self, data, flags, error)) return NULL; return g_steal_pointer (&self); } diff --git a/src/fu-archive.h b/src/fu-archive.h index c786de622..1165ecd01 100644 --- a/src/fu-archive.h +++ b/src/fu-archive.h @@ -15,9 +15,18 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (FuArchive, fu_archive, FU, ARCHIVE, GObject) +/** + * FwupdError: + * @FU_ARCHIVE_FLAG_NONE: No flags set + * @FU_ARCHIVE_FLAG_IGNORE_PATH: Ignore any path component + * + * The flags to use when loading the archive. + **/ typedef enum { FU_ARCHIVE_FLAG_NONE = 0, - FU_ARCHIVE_FLAGS_LAST + FU_ARCHIVE_FLAG_IGNORE_PATH = 1 << 0, + /*< private >*/ + FU_ARCHIVE_FLAG_LAST } FuArchiveFlags; FuArchive *fu_archive_new (GBytes *data, From 91a3eac28d74bff90e45f32aa918831e4134fb4f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 29 Nov 2018 22:35:58 -0600 Subject: [PATCH 106/254] contrib: Add a simple python3 client The client uses GObject introspection to use the libfwupd2 library. The client offers a reduced set of commands, but may be useful in some environments. --- contrib/simple_client.py | 126 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100755 contrib/simple_client.py diff --git a/contrib/simple_client.py b/contrib/simple_client.py new file mode 100755 index 000000000..0865a2e61 --- /dev/null +++ b/contrib/simple_client.py @@ -0,0 +1,126 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1+ +"""A simple fwupd frontend""" +import sys +import os +import gi +from gi.repository import GLib +gi.require_version('Fwupd', '2.0') +from gi.repository import Fwupd #pylint: disable=wrong-import-position + +class Progress(): + """Class to track the signal changes of progress events""" + def __init__(self): + self.device = None + self.status = None + self.percent = 0 + self.erase = 0 + + def device_changed(self, new_device): + """Indicate new device string to track""" + if self.device != new_device: + self.device = new_device + print("\nUpdating %s" % self.device) + + def status_changed(self, percent, status): + """Indicate new status string or % complete to track""" + if self.status != status or self.percent != percent: + for i in range(0, self.erase): + sys.stdout.write("\b \b") + self.status = status + self.percent = percent + status_str = "[" + for i in range(0, 50): + if i < percent/2: + status_str += '*' + else: + status_str += ' ' + status_str += "] %d%% %s" %(percent, status) + status_str.erase = len(status_str) + sys.stdout.write(status_str) + sys.stdout.flush() + if 'idle' in status: + sys.stdout.write("\n") + +def parse_args(): + """Parse arguments for this client""" + import argparse + parser = argparse.ArgumentParser(description="Interact with fwupd daemon") + parser.add_argument("--allow-older", action="store_true", + help="Install older payloads(default False)") + parser.add_argument("--allow-reinstall", action="store_true", + help="Reinstall payloads(default False)") + parser.add_argument("command", choices=["get-devices", + "get-details", + "install"], help="What to do") + parser.add_argument('cab', nargs='?', help='CAB file') + parser.add_argument('deviceid', nargs='?', + help='DeviceID to operate on(optional)') + args = parser.parse_args() + return args + +def get_devices(client): + """Use fwupd client to fetch devices""" + devices = client.get_devices() + for item in devices: + print(item.to_string()) + +def get_details(client, cab): + """Use fwupd client to fetch details for a CAB file""" + devices = client.get_details(cab, None) + for device in devices: + print(device.to_string()) + +def status_changed(client, spec, progress): #pylint: disable=unused-argument + """Signal emitted by fwupd daemon indicating status changed""" + progress.status_changed(client.get_percentage(), + Fwupd.status_to_string(client.get_status())) + +def device_changed(client, device, progress): #pylint: disable=unused-argument + """Signal emitted by fwupd daemon indicating active device changed""" + progress.device_changed(device.get_name()) + +def install(client, cab, target, older, reinstall): + """Use fwupd client to install CAB file to applicable devices""" + # FWUPD_DEVICE_ID_ANY + if not target: + target = '*' + flags = Fwupd.InstallFlags.NONE + if older: + flags |= Fwupd.InstallFlags.ALLOW_OLDER + if reinstall: + flags |= Fwupd.InstallFlags.ALLOW_REINSTALL + progress = Progress() + parent = super(client.__class__, client) + parent.connect('device-changed', device_changed, progress) + parent.connect('notify::percentage', status_changed, progress) + parent.connect('notify::status', status_changed, progress) + try: + client.install(target, cab, flags, None) + except GLib.Error as glib_err: #pylint: disable=catching-non-exception + progress.status_changed(0, 'idle') + print("%s" % glib_err) + sys.exit(1) + +def check_cab(cab): + """Check that CAB file exists""" + if not cab: + print("Need to specify payload") + sys.exit(1) + if not os.path.isfile(cab): + print("%s doesn't exist or isn't a file" % cab) + sys.exit(1) + +if __name__ == '__main__': + ARGS = parse_args() + CLIENT = Fwupd.Client() + CLIENT.connect() + + if ARGS.command == "get-devices": + get_devices(CLIENT) + elif ARGS.command == "get-details": + check_cab(ARGS.cab) + get_details(CLIENT, ARGS.cab) + elif ARGS.command == "install": + check_cab(ARGS.cab) + install(CLIENT, ARGS.cab, ARGS.deviceid, ARGS.allow_older, ARGS.allow_reinstall) From cd2fb3eb6238d43edda69d8dd8f4c2fb0b882fa7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 29 Nov 2018 19:58:09 +0000 Subject: [PATCH 107/254] Check plugins set error on failure Don't explode in a ball of flames if the plugin forgets to set the error. This at least gives us a journal warning when a plugin goes crazy. --- src/fu-plugin.c | 234 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 188 insertions(+), 46 deletions(-) diff --git a/src/fu-plugin.c b/src/fu-plugin.c index 58166fbda..7cd8ffc74 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -776,6 +776,7 @@ fu_plugin_runner_startup (FuPlugin *self, GError **error) { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -790,8 +791,18 @@ fu_plugin_runner_startup (FuPlugin *self, GError **error) if (func == NULL) return TRUE; g_debug ("performing startup() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to startup %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for startup()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to startup using %s: ", + priv->name); return FALSE; } return TRUE; @@ -847,6 +858,7 @@ fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device, { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -861,10 +873,18 @@ fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device, if (func == NULL) return TRUE; g_debug ("performing %s() on %s", symbol_name + 10, priv->name); - if (!func (self, device, error)) { - g_prefix_error (error, "failed to run %s() on %s: ", - symbol_name + 10, - priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); return FALSE; } return TRUE; @@ -877,6 +897,7 @@ fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginFlaggedDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -891,10 +912,18 @@ fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags if (func == NULL) return TRUE; g_debug ("performing %s() on %s", symbol_name + 10, priv->name); - if (!func (self, flags, device, error)) { - g_prefix_error (error, "failed to run %s() on %s: ", - symbol_name + 10, - priv->name); + if (!func (self, flags, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); return FALSE; } return TRUE; @@ -907,6 +936,7 @@ fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices, { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceArrayFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -921,10 +951,18 @@ fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices, if (func == NULL) return TRUE; g_debug ("performing %s() on %s", symbol_name + 10, priv->name); - if (!func (self, devices, error)) { - g_prefix_error (error, "failed to run %s() on %s: ", - symbol_name + 10, - priv->name); + if (!func (self, devices, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); return FALSE; } return TRUE; @@ -935,6 +973,7 @@ fu_plugin_runner_coldplug (FuPlugin *self, GError **error) { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -949,8 +988,17 @@ fu_plugin_runner_coldplug (FuPlugin *self, GError **error) if (func == NULL) return TRUE; g_debug ("performing coldplug() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug using %s: ", priv->name); return FALSE; } return TRUE; @@ -961,6 +1009,7 @@ fu_plugin_runner_recoldplug (FuPlugin *self, GError **error) { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -975,8 +1024,18 @@ fu_plugin_runner_recoldplug (FuPlugin *self, GError **error) if (func == NULL) return TRUE; g_debug ("performing recoldplug() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to recoldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for recoldplug()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to recoldplug using %s: ", + priv->name); return FALSE; } return TRUE; @@ -987,6 +1046,7 @@ fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error) { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1001,8 +1061,18 @@ fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error) if (func == NULL) return TRUE; g_debug ("performing coldplug_prepare() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to prepare for coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug_prepare()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug_prepare using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1013,6 +1083,7 @@ fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error) { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1027,8 +1098,18 @@ fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error) if (func == NULL) return TRUE; g_debug ("performing coldplug_cleanup() on %s", priv->name); - if (!func (self, error)) { - g_prefix_error (error, "failed to cleanup coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug_cleanup()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug_cleanup using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1116,6 +1197,7 @@ fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError * { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginUsbDeviceAddedFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1127,9 +1209,22 @@ fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError * /* optional */ g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func); - if (func != NULL) { - g_debug ("performing usb_device_added() on %s", priv->name); - return func (self, device, error); + if (func == NULL) + return TRUE; + g_debug ("performing usb_device_added() on %s", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for usb_device_added()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to add device using on %s: ", + priv->name); + return FALSE; } return TRUE; } @@ -1139,6 +1234,7 @@ fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginUdevDeviceAddedFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1150,9 +1246,22 @@ fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError /* optional */ g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func); - if (func != NULL) { - g_debug ("performing udev_device_added() on %s", priv->name); - return func (self, device, error); + if (func == NULL) + return TRUE; + g_debug ("performing udev_device_added() on %s", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for udev_device_added()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to add device using on %s: ", + priv->name); + return FALSE; } return TRUE; } @@ -1265,6 +1374,7 @@ fu_plugin_runner_verify (FuPlugin *self, FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginVerifyFunc func = NULL; GPtrArray *checksums; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1283,8 +1393,18 @@ fu_plugin_runner_verify (FuPlugin *self, if (func == NULL) return TRUE; g_debug ("performing verify() on %s", priv->name); - if (!func (self, device, flags, error)) { - g_prefix_error (error, "failed to verify %s: ", priv->name); + if (!func (self, device, flags, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for verify()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to verify using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1330,7 +1450,7 @@ fu_plugin_runner_update (FuPlugin *self, FuPluginUpdateFunc update_func; g_autoptr(FuHistory) history = NULL; g_autoptr(FuDevice) device_pending = NULL; - GError *error_update = NULL; + g_autoptr(GError) error_local = NULL; GPtrArray *checksums; /* not enabled */ @@ -1377,18 +1497,18 @@ fu_plugin_runner_update (FuPlugin *self, /* online */ history = fu_history_new (); device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL); - if (!update_func (self, device, blob_fw, flags, &error_update)) { - if (error_update == NULL) { - g_critical ("plugin %s returned FALSE from UpdateFunc " - "but did not set error!", - fu_plugin_get_name (self)); - g_set_error_literal (&error_update, + if (!update_func (self, device, blob_fw, flags, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for update()", + priv->name); + g_set_error_literal (&error_local, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "unspecified error"); + return FALSE; } - fu_device_set_update_error (device, error_update->message); - g_propagate_error (error, error_update); + fu_device_set_update_error (device, error_local->message); + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; } @@ -1412,15 +1532,15 @@ fu_plugin_runner_update (FuPlugin *self, release = fu_device_get_release_default (device_pending); tmp = fwupd_release_get_filename (release); if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) { - g_autoptr(GError) error_local = NULL; + g_autoptr(GError) error_delete = NULL; g_autoptr(GFile) file = NULL; file = g_file_new_for_path (tmp); - if (!g_file_delete (file, NULL, &error_local)) { + if (!g_file_delete (file, NULL, &error_delete)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to delete %s: %s", - tmp, error_local->message); + tmp, error_delete->message); return FALSE; } } @@ -1433,6 +1553,7 @@ fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1447,8 +1568,18 @@ fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error if (func == NULL) return TRUE; g_debug ("performing clear_result() on %s", priv->name); - if (!func (self, device, error)) { - g_prefix_error (error, "failed to clear_result %s: ", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for clear_result()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to clear_result using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1459,6 +1590,7 @@ fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error) { FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1473,8 +1605,18 @@ fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error) if (func == NULL) return TRUE; g_debug ("performing get_results() on %s", priv->name); - if (!func (self, device, error)) { - g_prefix_error (error, "failed to get_results %s: ", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for get_results()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to get_results using %s: ", + priv->name); return FALSE; } return TRUE; From 6dc8680e15be28f60a081c18749a823492fa3412 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Nov 2018 09:15:00 +0000 Subject: [PATCH 108/254] amt: Fix a crash if AMT returns an empty response Mixing integer return values and GError is never a good idea. Fixes https://bugzilla.redhat.com/attachment.cgi?id=1510083 --- plugins/amt/fu-plugin-amt.c | 268 ++++++++++++++++++++++-------------- 1 file changed, 165 insertions(+), 103 deletions(-) diff --git a/plugins/amt/fu-plugin-amt.c b/plugins/amt/fu-plugin-amt.c index 1f74c1622..ff5ea0e96 100644 --- a/plugins/amt/fu-plugin-amt.c +++ b/plugins/amt/fu-plugin-amt.c @@ -86,27 +86,26 @@ mei_context_new (mei_context *ctx, return TRUE; } -static gssize +static gboolean mei_recv_msg (mei_context *ctx, guchar *buffer, - gssize len, unsigned long timeout, GError **error) + gssize len, guint32 *readsz, unsigned long timeout, GError **error) { gssize rc; - - g_debug ("call read length = %zd", len); rc = read (ctx->fd, buffer, len); if (rc < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "read failed with status %zd %s", - rc, strerror(errno)); - } else { - g_debug ("read succeeded with result %zd", rc); + rc, strerror(errno)); + return FALSE; } - return rc; + if (readsz != NULL) + *readsz = rc; + return TRUE; } -static gssize +static gboolean mei_send_msg (mei_context *ctx, const guchar *buffer, gssize len, unsigned long timeout, GError **error) { @@ -118,7 +117,6 @@ mei_send_msg (mei_context *ctx, const guchar *buffer, tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000000; - g_debug ("call write length = %zd", len); written = write (ctx->fd, buffer, len); if (written < 0) { g_set_error (error, @@ -126,16 +124,22 @@ mei_send_msg (mei_context *ctx, const guchar *buffer, FWUPD_ERROR_WRITE, "write failed with status %zd %s", written, strerror(errno)); - return -errno; + return FALSE; + } + if (written != len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "only wrote %" G_GSSIZE_FORMAT " of %" G_GSSIZE_FORMAT, + written, len); + return FALSE; } FD_ZERO(&set); FD_SET(ctx->fd, &set); rc = select (ctx->fd + 1 , &set, NULL, NULL, &tv); - if (rc > 0 && FD_ISSET(ctx->fd, &set)) { - g_debug ("write success"); - return written; - } + if (rc > 0 && FD_ISSET(ctx->fd, &set)) + return TRUE; /* timed out */ if (rc == 0) { @@ -143,7 +147,7 @@ mei_send_msg (mei_context *ctx, const guchar *buffer, FWUPD_ERROR, FWUPD_ERROR_WRITE, "write failed on timeout with status"); - return 0; + return FALSE; } /* rc < 0 */ @@ -151,7 +155,7 @@ mei_send_msg (mei_context *ctx, const guchar *buffer, FWUPD_ERROR, FWUPD_ERROR_WRITE, "write failed on select with status %zd", rc); - return rc; + return FALSE; } /*************************************************************************** @@ -254,50 +258,91 @@ struct amt_host_if { mei_context mei_cl; }; -static guint32 -amt_verify_code_versions (const struct amt_host_if_resp_header *resp) +static gboolean +amt_verify_code_versions (const struct amt_host_if_resp_header *resp, GError **error) { struct amt_code_versions *code_ver = (struct amt_code_versions *)resp->data; gsize code_ver_len = resp->header.length - sizeof(guint32); guint32 ver_type_cnt = code_ver_len - sizeof(code_ver->bios) - sizeof(code_ver->count); - if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) - return AMT_STATUS_INTERNAL_ERROR; + if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid offset"); + return FALSE; + } for (guint32 i = 0; i < code_ver->count; i++) { guint32 len = code_ver->versions[i].description.length; - if (len > AMT_UNICODE_STRING_LEN) - return AMT_STATUS_INTERNAL_ERROR; + if (len > AMT_UNICODE_STRING_LEN) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "string too large"); + return FALSE; + } len = code_ver->versions[i].version.length; if (code_ver->versions[i].version.string[len] != '\0' || - len != strlen(code_ver->versions[i].version.string)) - return AMT_STATUS_INTERNAL_ERROR; + len != strlen(code_ver->versions[i].version.string)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "string was invalid size"); + return FALSE; + } } - return AMT_STATUS_SUCCESS; + return TRUE; } -static guint32 -amt_verify_response_header (guint32 command, - const struct amt_host_if_msg_header *resp_hdr, - guint32 response_size) +static gboolean +amt_status_set_error (guint32 status, GError **error) { - if (response_size < sizeof(struct amt_host_if_resp_header)) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (response_size != (resp_hdr->length + - sizeof(struct amt_host_if_msg_header))) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->command != command) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->_reserved != 0) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->version.major != AMT_MAJOR_VERSION || - resp_hdr->version.minor < AMT_MINOR_VERSION) { - return AMT_STATUS_INTERNAL_ERROR; + if (status == AMT_STATUS_SUCCESS) + return TRUE; + if (status == AMT_STATUS_INTERNAL_ERROR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "internal error"); + return FALSE; } - return AMT_STATUS_SUCCESS; + if (status == AMT_STATUS_NOT_READY) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "not ready"); + return FALSE; + } + if (status == AMT_STATUS_INVALID_AMT_MODE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid AMT mode"); + return FALSE; + } + if (status == AMT_STATUS_INVALID_MESSAGE_LENGTH) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid message length"); + return FALSE; + } + if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Intel AMT is disabled"); + return FALSE; + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unknown error"); + return FALSE; } -static guint32 +static gboolean amt_host_if_call (mei_context *mei_cl, const guchar *command, gssize command_sz, @@ -309,53 +354,86 @@ amt_host_if_call (mei_context *mei_cl, { guint32 in_buf_sz; guint32 out_buf_sz; - gssize written; - guint32 status; struct amt_host_if_resp_header *msg_hdr; in_buf_sz = mei_cl->buf_size; *read_buf = (guint8 *) g_malloc0 (in_buf_sz); msg_hdr = (struct amt_host_if_resp_header *) *read_buf; - written = mei_send_msg (mei_cl, command, command_sz, send_timeout, error); - if (written != command_sz) - return AMT_STATUS_INTERNAL_ERROR; - - out_buf_sz = mei_recv_msg (mei_cl, *read_buf, in_buf_sz, 2000, error); - if (out_buf_sz <= 0) - return AMT_STATUS_HOST_IF_EMPTY_RESPONSE; - - status = msg_hdr->status; - if (status != AMT_STATUS_SUCCESS) - return status; - - status = amt_verify_response_header(rcmd, &msg_hdr->header, out_buf_sz); - if (status != AMT_STATUS_SUCCESS) - return status; - - if (expected_sz && expected_sz != out_buf_sz) - return AMT_STATUS_INTERNAL_ERROR; - - return AMT_STATUS_SUCCESS; + if (!mei_send_msg (mei_cl, command, command_sz, send_timeout, error)) + return FALSE; + if (!mei_recv_msg (mei_cl, *read_buf, in_buf_sz, &out_buf_sz, 2000, error)) + return FALSE; + if (out_buf_sz <= 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "empty response"); + return FALSE; + } + if (expected_sz && expected_sz != out_buf_sz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "expected %u but got %" G_GUINT32_FORMAT, + expected_sz, out_buf_sz); + return FALSE; + } + if (!amt_status_set_error (msg_hdr->status, error)) + return FALSE; + if (out_buf_sz < sizeof(struct amt_host_if_resp_header)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: too small"); + return FALSE; + } + if (out_buf_sz != (msg_hdr->header.length + + sizeof(struct amt_host_if_msg_header))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: headerlen"); + return FALSE; + } + if (msg_hdr->header.command != rcmd) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: rcmd"); + return FALSE; + } + if (msg_hdr->header._reserved != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: reserved"); + return FALSE; + } + if (msg_hdr->header.version.major != AMT_MAJOR_VERSION || + msg_hdr->header.version.minor < AMT_MINOR_VERSION) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: version"); + return FALSE; + } + return TRUE; } -static guint32 +static gboolean amt_get_provisioning_state (mei_context *mei_cl, guint8 *state, GError **error) { g_autofree struct amt_host_if_resp_header *response = NULL; - guint32 status; - - status = amt_host_if_call (mei_cl, - (const guchar *)&PROVISIONING_STATE_REQUEST, - sizeof(PROVISIONING_STATE_REQUEST), - (guint8 **)&response, - AMT_HOST_IF_PROVISIONING_STATE_RESPONSE, 0, - 5000, error); - if (status != AMT_STATUS_SUCCESS) { + if (!amt_host_if_call (mei_cl, + (const guchar *)&PROVISIONING_STATE_REQUEST, + sizeof(PROVISIONING_STATE_REQUEST), + (guint8 **)&response, + AMT_HOST_IF_PROVISIONING_STATE_RESPONSE, 0, + 5000, error)) { g_prefix_error (error, "unable to get provisioning state: "); return FALSE; } - *state = response->data[0]; return TRUE; } @@ -369,7 +447,6 @@ static FuDevice * fu_plugin_amt_create_device (GError **error) { gchar guid_buf[37]; - guint32 status; guint8 state; struct amt_code_versions ver; uuid_t uu; @@ -387,33 +464,18 @@ fu_plugin_amt_create_device (GError **error) return NULL; /* check version */ - status = amt_host_if_call (ctx, - (const guchar *) &CODE_VERSION_REQ, - sizeof(CODE_VERSION_REQ), - (guint8 **) &response, - AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0, - 5000, - error); - if (status != AMT_STATUS_SUCCESS) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to check version"); + if (!amt_host_if_call (ctx, + (const guchar *) &CODE_VERSION_REQ, + sizeof(CODE_VERSION_REQ), + (guint8 **) &response, + AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0, + 5000, + error)) { + g_prefix_error (error, "Failed to check version: "); return NULL; } - status = amt_verify_code_versions (response); - if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Intel AMT is disabled"); - return NULL; - } - if (status != AMT_STATUS_SUCCESS) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Failed to verify code versions"); + if (!amt_verify_code_versions (response, error)) { + g_prefix_error (error, "failed to verify code versions: "); return NULL; } memcpy (&ver, response->data, sizeof(struct amt_code_versions)); From 7cd6d363e1f22d103dda0c087ba5d101378491f0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 30 Nov 2018 14:44:30 +0000 Subject: [PATCH 109/254] trivial: Correctly calculate the erase length for all locales This fixes the progressbar going crazy when using fwupdmgr with zh_CN. --- src/fu-progressbar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fu-progressbar.c b/src/fu-progressbar.c index d0d602912..6dc0f36d9 100644 --- a/src/fu-progressbar.c +++ b/src/fu-progressbar.c @@ -157,7 +157,7 @@ fu_progressbar_refresh (FuProgressbar *self, FwupdStatus status, guint percentag } title = fu_progressbar_status_to_string (status); g_string_append (str, title); - for (i = str->len; i < self->length_status; i++) + for (i = g_utf8_strlen (str->str, -1); i < self->length_status; i++) g_string_append_c (str, ' '); /* add progressbar */ @@ -186,7 +186,7 @@ fu_progressbar_refresh (FuProgressbar *self, FwupdStatus status, guint percentag /* dump to screen */ g_print ("%s", str->str); - self->to_erase = str->len - 2; + self->to_erase = str->len; /* done */ if (is_idle_newline) { From 1af48b13bd09c25bac218cb947063fc7055f7ecf Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 3 Dec 2018 11:51:17 +0000 Subject: [PATCH 110/254] Correctly parse format the version numbers correctly using old metadata The LVFS has always sent components with the old-style '' section rather than the new-style '' section, and when using appstream-glib we just accepted either element name. Although the LVFS has just been fixed to use the new name, old metadata might be present on the system already. When all clients have downloaded new metadata we can revert this, perhaps in a couple of weeks time. Until then, the belt-and-braces approach is probably a good idea. Fixes https://github.com/hughsie/fwupd/issues/874 --- src/fu-engine.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 7904f21ab..8f6dc40fb 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1774,6 +1774,17 @@ fu_engine_is_device_supported (FuEngine *self, FuDevice *device) return TRUE; } +static gboolean +fu_engine_appstream_upgrade_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + if (g_strcmp0 (xb_builder_node_get_element (bn), "metadata") == 0) + xb_builder_node_set_element (bn, "custom"); + return TRUE; +} + static gboolean fu_engine_load_metadata_store (FuEngine *self, GError **error) { @@ -1801,6 +1812,7 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) const gchar *path = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilderFixup) fixup = NULL; g_autoptr(XbBuilderNode) custom = NULL; g_autoptr(XbBuilderSource) source = xb_builder_source_new (); @@ -1827,6 +1839,13 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) continue; } + /* fix up any legacy installed files */ + fixup = xb_builder_fixup_new ("AppStreamUpgrade", + fu_engine_appstream_upgrade_cb, + self, NULL); + xb_builder_fixup_set_max_depth (fixup, 3); + xb_builder_source_add_fixup (source, fixup); + /* add metadata */ custom = xb_builder_node_new ("custom"); xb_builder_node_insert_text (custom, From b27a2520cc11fd234420041bcb2cf2c33e527084 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 3 Dec 2018 12:59:44 +0000 Subject: [PATCH 111/254] dfu: Require a specific USB class and subclass for DFU mode This makes startup quicker as we no longer have to probe every USB device, and is now possible with the new GUIDs we added. Devices not using the specification-provided values can (and already are) worked around with quirks. --- plugins/dfu/dfu.quirk | 5 +++++ plugins/dfu/fu-plugin-dfu.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/plugins/dfu/dfu.quirk b/plugins/dfu/dfu.quirk index 8c7181751..182fcb830 100644 --- a/plugins/dfu/dfu.quirk +++ b/plugins/dfu/dfu.quirk @@ -1,3 +1,7 @@ +# All DFU devices +[DeviceInstanceId=USB\CLASS_FE&SUBCLASS_01] +Plugin = dfu + # on PC platforms the DW1820A firmware is loaded at runtime and can't # be stored on the device itself as the flash chip is unpopulated [DeviceInstanceId=USB\VID_0A5C&PID_6412] @@ -130,6 +134,7 @@ DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode Plugin = dfu DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode [DeviceInstanceId=USB\VID_03EB&PID_2FF4] +Plugin = dfu DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode # Atmel XMEGA Bootloader diff --git a/plugins/dfu/fu-plugin-dfu.c b/plugins/dfu/fu-plugin-dfu.c index 64af9951d..4ebd7a651 100644 --- a/plugins/dfu/fu-plugin-dfu.c +++ b/plugins/dfu/fu-plugin-dfu.c @@ -10,6 +10,12 @@ #include "dfu-device.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); +} + static void fu_plugin_dfu_state_changed_cb (DfuDevice *device, DfuState state, From 0585172c17522f03804fe45e98222c3e88db804a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 3 Dec 2018 12:52:16 +0000 Subject: [PATCH 112/254] trivial: Document the expected plugin firmware formats --- plugins/altos/README.md | 6 ++++++ plugins/colorhug/README.md | 6 ++++++ plugins/csr/README.md | 32 ++++++++++++++++++++++++++++++++ plugins/dell-dock/README.md | 6 ++++++ plugins/dfu/README.md | 6 ++++++ plugins/ebitdo/README.md | 7 +++++++ plugins/flashrom/README.md | 7 +++++++ plugins/nvme/README.md | 6 ++++++ plugins/redfish/README.md | 6 ++++++ plugins/rts54hid/README.md | 6 ++++++ plugins/rts54hub/README.md | 6 ++++++ plugins/synapticsmst/README.md | 6 ++++++ plugins/thunderbolt/README.md | 6 ++++++ plugins/uefi/README.md | 9 +++++++++ plugins/unifying/README.md | 6 ++++++ plugins/wacom-usb/README.md | 6 ++++++ 16 files changed, 127 insertions(+) create mode 100644 plugins/csr/README.md diff --git a/plugins/altos/README.md b/plugins/altos/README.md index d683807ed..8d0eeabb9 100644 --- a/plugins/altos/README.md +++ b/plugins/altos/README.md @@ -15,6 +15,12 @@ The bootloader communication is not handled in the kernel, and a tty device is created so userspace can communicate with the hardware. Commands the bootloader accept are as follows: +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +ELF file format. The firmware image is inserted into the `.text` section. + GUID Generation --------------- diff --git a/plugins/colorhug/README.md b/plugins/colorhug/README.md index 867d03dae..38747241d 100644 --- a/plugins/colorhug/README.md +++ b/plugins/colorhug/README.md @@ -11,6 +11,12 @@ accurate color matching. ColorHug versions 1 and 2 support a custom HID-based flashing protocol, but version 3 (ColorHug+) has now switched to DFU. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a packed binary file format. + GUID Generation --------------- diff --git a/plugins/csr/README.md b/plugins/csr/README.md new file mode 100644 index 000000000..645da33b6 --- /dev/null +++ b/plugins/csr/README.md @@ -0,0 +1,32 @@ +CSR Support +=========== + +Introduction +------------ + +CSR is often called “driverless DFU” and is used only by BlueCore chips from +Cambridge Silicon Radio (now owned by Qualcomm). The driverless just means that +it's DFU like, and is routed over HID. + +CSR is a ODM that makes most of the Bluetooth audio chips in vendor hardware. +The hardware vendor can enable or disable features on the CSR microcontroller +depending on licensing options (for instance echo cancellation), and there’s +even a little virtual machine to do simple vendor-specific things. + +All the CSR chips are updatable in-field, and most vendors issue updates to fix +sound quality issues or to add support for new protocols or devices. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +DFU file format. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0A12&PID_1337&REV_2520` + * `USB\VID_0A12&PID_1337` + * `USB\VID_0A12` diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index 0c2cf1081..1800c1604 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -25,6 +25,12 @@ When this plugin is used, devices present in other plugins may be shown in the topology of this dock. This is intentional as this plugin works together with those plugins to manage the flashing of all components. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract several firmware +blobs with an unspecified binary file format. + GUID Generation --------------- diff --git a/plugins/dfu/README.md b/plugins/dfu/README.md index 1f5690659..6dcc0a79b 100644 --- a/plugins/dfu/README.md +++ b/plugins/dfu/README.md @@ -7,6 +7,12 @@ Introduction Device Firmware Update is a standard that allows USB devices to be easily and safely updated by any operating system. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +DFU or DfuSe file format. + GUID Generation --------------- diff --git a/plugins/ebitdo/README.md b/plugins/ebitdo/README.md index 157e77623..3e16f76a8 100644 --- a/plugins/ebitdo/README.md +++ b/plugins/ebitdo/README.md @@ -12,6 +12,13 @@ library and is possible thanks to the vendor open sourcing the flashing tool. The 8Bitdo devices share legacy USB VID/PIDs with other projects and so we have to be a bit careful to not claim other devices as our own. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. The binary file has a vendor-specific header +that is used when flashing the image. + GUID Generation --------------- diff --git a/plugins/flashrom/README.md b/plugins/flashrom/README.md index a65bc9104..cce935dce 100644 --- a/plugins/flashrom/README.md +++ b/plugins/flashrom/README.md @@ -6,6 +6,13 @@ Introduction This plugin uses `flashrom` to update the system firmware. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format, which is typically the raw input for an +EEPROM programmer. + GUID Generation --------------- diff --git a/plugins/nvme/README.md b/plugins/nvme/README.md index da9cc9dd1..1247521cc 100644 --- a/plugins/nvme/README.md +++ b/plugins/nvme/README.md @@ -11,6 +11,12 @@ firmware file. Firmware is sent in 4kB chunks and activated on next reboot. The device GUID is read from the vendor specific area and if not found then generated from the trimmed model string. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + GUID Generation --------------- diff --git a/plugins/redfish/README.md b/plugins/redfish/README.md index 217a42151..df3d1683b 100644 --- a/plugins/redfish/README.md +++ b/plugins/redfish/README.md @@ -10,6 +10,12 @@ simple and secure management of modern scalable platform hardware. By specifying a RESTful interface and utilizing JSON and OData, Redfish helps customers integrate solutions within their existing tool chains. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + GUID Generation --------------- diff --git a/plugins/rts54hid/README.md b/plugins/rts54hid/README.md index 53798d7de..dd9e3f967 100644 --- a/plugins/rts54hid/README.md +++ b/plugins/rts54hid/README.md @@ -10,6 +10,12 @@ device using the HUB update protocol. Other devices connected to the RTS54HIDxx using I2C will be supported soon. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + GUID Generation --------------- diff --git a/plugins/rts54hub/README.md b/plugins/rts54hub/README.md index dd17cbc5a..2f91ac98b 100644 --- a/plugins/rts54hub/README.md +++ b/plugins/rts54hub/README.md @@ -10,6 +10,12 @@ device using the HID update protocol. Other devices connected to the RTS54xx using I2C will be supported soon. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + GUID Generation --------------- diff --git a/plugins/synapticsmst/README.md b/plugins/synapticsmst/README.md index b32fa46b1..b5206e8dd 100644 --- a/plugins/synapticsmst/README.md +++ b/plugins/synapticsmst/README.md @@ -3,6 +3,12 @@ This plugin supports querying and flashing Synaptics MST hubs used in Dell systems and docks. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + GUID Generation --------------- diff --git a/plugins/thunderbolt/README.md b/plugins/thunderbolt/README.md index 7757f5b1d..9d48a12b5 100644 --- a/plugins/thunderbolt/README.md +++ b/plugins/thunderbolt/README.md @@ -9,6 +9,12 @@ allows the connection of external peripherals to a computer. Versions 1 and 2 use the same connector as Mini DisplayPort (MDP), whereas version 3 uses USB Type-C. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format, with vendor specific header. + GUID Generation --------------- diff --git a/plugins/uefi/README.md b/plugins/uefi/README.md index 7082bc9eb..ce0713791 100644 --- a/plugins/uefi/README.md +++ b/plugins/uefi/README.md @@ -11,6 +11,15 @@ With the UpdateCapsule boot service it can be used to update system firmware. If you don't want or need this functionality you can use the `-Dplugin_uefi=false` option. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +EFI capsule file format. + +See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf +for details. + GUID Generation --------------- diff --git a/plugins/unifying/README.md b/plugins/unifying/README.md index e724da15d..8f9497a99 100644 --- a/plugins/unifying/README.md +++ b/plugins/unifying/README.md @@ -16,6 +16,12 @@ supplied by Logitech. Additional constants were taken from the Solaar[2] project. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a vendor-specific format that appears to be a subset of the Intel HEX format. + GUID Generation --------------- diff --git a/plugins/wacom-usb/README.md b/plugins/wacom-usb/README.md index d5178bb1b..d40e319a4 100644 --- a/plugins/wacom-usb/README.md +++ b/plugins/wacom-usb/README.md @@ -16,6 +16,12 @@ programmed using a more complicated erase, write, verify algorithm based on a historical update protocol. The "sub-module" devices use a newer protocol, again based on HID, but are handled differently depending on thier type. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +SREC file format, with a custom vendor header. + GUID Generation --------------- From a07a80ff288e71e114cac20ea33f89a9f03e7e0d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 3 Dec 2018 14:57:33 +0000 Subject: [PATCH 113/254] Fix a regression when doing GetReleases on unsupported hardware With an indexed string we can return INVALID_ARGUMENT before the query actually runs if nothing matches. --- src/fu-engine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 8f6dc40fb..9c61bbb7c 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2520,7 +2520,8 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er } components = xb_silo_query (self->silo, xpath->str, 0, &error_local); if (components == NULL) { - if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { + 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_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, From 1c4e06925ccb607d52cb69c6e7539dc32ad66623 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 3 Dec 2018 14:34:40 +0000 Subject: [PATCH 114/254] trivial: Speed up daemon startup Require a quirk match for Unifying hardware to avoid probing a lot of USB devices at startup. --- plugins/unifying/fu-plugin-unifying.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/unifying/fu-plugin-unifying.c b/plugins/unifying/fu-plugin-unifying.c index 727bd4749..6bd35350b 100644 --- a/plugins/unifying/fu-plugin-unifying.c +++ b/plugins/unifying/fu-plugin-unifying.c @@ -173,5 +173,6 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_udev_subsystem (plugin, "hidraw"); } From b4fd12a4c6d877820e87598edf5ef5e4867735ba Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 27 Nov 2018 21:32:53 +0000 Subject: [PATCH 115/254] Add a plugin to update hardware that supports fastboot --- contrib/fwupd.spec.in | 1 + plugins/fastboot/README.md | 36 + plugins/fastboot/data/android/flashfile.xml | 6 + plugins/fastboot/data/lsusb.txt | 58 ++ plugins/fastboot/data/qfil/partition_nand.xml | 21 + plugins/fastboot/fastboot.quirk | 3 + plugins/fastboot/fu-fastboot-device.c | 696 ++++++++++++++++++ plugins/fastboot/fu-fastboot-device.h | 21 + plugins/fastboot/fu-plugin-fastboot.c | 62 ++ plugins/fastboot/meson.build | 23 + plugins/meson.build | 1 + 11 files changed, 928 insertions(+) create mode 100644 plugins/fastboot/README.md create mode 100644 plugins/fastboot/data/android/flashfile.xml create mode 100644 plugins/fastboot/data/lsusb.txt create mode 100644 plugins/fastboot/data/qfil/partition_nand.xml create mode 100644 plugins/fastboot/fastboot.quirk create mode 100644 plugins/fastboot/fu-fastboot-device.c create mode 100644 plugins/fastboot/fu-fastboot-device.h create mode 100644 plugins/fastboot/fu-plugin-fastboot.c create mode 100644 plugins/fastboot/meson.build diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 28a55bc43..ab55c3b6f 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -265,6 +265,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_dell_dock.so %{_libdir}/fwupd-plugins-3/libfu_plugin_dfu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ebitdo.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so %{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so %{_libdir}/fwupd-plugins-3/libfu_plugin_nitrokey.so %if 0%{?have_uefi} diff --git a/plugins/fastboot/README.md b/plugins/fastboot/README.md new file mode 100644 index 000000000..328cedfb5 --- /dev/null +++ b/plugins/fastboot/README.md @@ -0,0 +1,36 @@ +Fastboot Support +================ + +Introduction +------------ + +This plugin is used to update hardware that uses the fastboot protocol. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmare blob in +ZIP file format. Inside the zip file must be all the firmware images for each +partition and a manifest file. The partition images can be in any format, but +the manifest must be either an Android `flashfile.xml` format file, or a QFIL +`partition_nand.xml` format file. + +For both types, all partitions with a defined image found in the zip file will +be updated. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_18D1&PID_4EE0&REV_0001` + * `USB\VID_18D1&PID_4EE0` + * `USB\VID_18D1` + +Quirk use +--------- +This plugin uses the following plugin-specific quirk: + +| Quirk | Description | Minimum fwupd version | +|------------------------|----------------------------------|-----------------------| +| `FastbootBlockSize` | Block size to use for transfers | 1.2.2 | diff --git a/plugins/fastboot/data/android/flashfile.xml b/plugins/fastboot/data/android/flashfile.xml new file mode 100644 index 000000000..ca70589d7 --- /dev/null +++ b/plugins/fastboot/data/android/flashfile.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/plugins/fastboot/data/lsusb.txt b/plugins/fastboot/data/lsusb.txt new file mode 100644 index 000000000..424c956f9 --- /dev/null +++ b/plugins/fastboot/data/lsusb.txt @@ -0,0 +1,58 @@ +Bus 001 Device 025: ID 18d1:4ee0 Google Inc. Nexus 4 (bootloader) +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x18d1 Google Inc. + idProduct 0x4ee0 Nexus 4 (bootloader) + bcdDevice 1.00 + iManufacturer 1 Google + iProduct 2 Android + iSerial 3 034412a082919b5c + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 66 + bInterfaceProtocol 3 + iInterface 4 fastboot + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/plugins/fastboot/data/qfil/partition_nand.xml b/plugins/fastboot/data/qfil/partition_nand.xml new file mode 100644 index 000000000..503318cce --- /dev/null +++ b/plugins/fastboot/data/qfil/partition_nand.xml @@ -0,0 +1,21 @@ + + + + 0xAA7D1B9A + 0x1F7D48BC + + 0x4 + + + 0:SBL + 0x8 + 0x2 + 0 + 0xFF + 0x01 + 0x00 + 0xFE + sbl1.mbn + + + diff --git a/plugins/fastboot/fastboot.quirk b/plugins/fastboot/fastboot.quirk new file mode 100644 index 000000000..7f16f2e91 --- /dev/null +++ b/plugins/fastboot/fastboot.quirk @@ -0,0 +1,3 @@ +# All fastboot devices +[DeviceInstanceId=USB\CLASS_FF&SUBCLASS_42&PROT_03] +Plugin = fastboot diff --git a/plugins/fastboot/fu-fastboot-device.c b/plugins/fastboot/fu-fastboot-device.c new file mode 100644 index 000000000..f4674ae27 --- /dev/null +++ b/plugins/fastboot/fu-fastboot-device.c @@ -0,0 +1,696 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-archive.h" +#include "fu-chunk.h" +#include "fu-fastboot-device.h" + +#define FASTBOOT_TRANSACTION_TIMEOUT 1000 /* ms */ +#define FASTBOOT_TRANSACTION_RETRY_MAX 600 +#define FASTBOOT_EP_IN 0x81 +#define FASTBOOT_EP_OUT 0x01 +#define FASTBOOT_CMD_BUFSZ 64 /* bytes */ + +struct _FuFastbootDevice { + FuUsbDevice parent_instance; + gboolean secure; + guint blocksz; + guint8 intf_nr; +}; + +G_DEFINE_TYPE (FuFastbootDevice, fu_fastboot_device, FU_TYPE_USB_DEVICE) + +static void +fu_fastboot_device_to_string (FuDevice *device, GString *str) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + g_string_append (str, " FuFastbootDevice:\n"); + g_string_append_printf (str, " intf:\t0x%02x\n", (guint) self->intf_nr); + g_string_append_printf (str, " secure:\t%i\n", self->secure); + g_string_append_printf (str, " blocksz:\t%u\n", self->blocksz); +} + +static gboolean +fu_fastboot_device_probe (FuDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GUsbInterface) intf = NULL; + + /* find the correct fastboot interface */ + intf = g_usb_device_get_interface (usb_device, 0xff, 0x42, 0x03, error); + if (intf == NULL) + return FALSE; + self->intf_nr = g_usb_interface_get_number (intf); + return TRUE; +} + +static gboolean +fu_fastboot_device_open (FuUsbDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + if (!g_usb_device_claim_interface (usb_device, self->intf_nr, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static void +fu_fastboot_buffer_dump (const gchar *title, const guint8 *buf, gsize sz) +{ + if (g_getenv ("FWUPD_FASTBOOT_VERBOSE") == NULL) + return; + g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); + for (gsize i = 0; i < sz; i++) { + g_print ("%02x[%c] ", buf[i], g_ascii_isprint (buf[i]) ? buf[i] : '?'); + if (i > 0 && (i + 1) % 256 == 0) + g_print ("\n"); + } + g_print ("\n"); +} + +static gboolean +fu_fastboot_device_write (FuDevice *device, const guint8 *buf, gsize buflen, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + gboolean ret; + gsize actual_len = 0; + g_autofree guint8 *buf2 = g_memdup (buf, (guint) buflen); + + fu_fastboot_buffer_dump ("writing", buf, buflen); + ret = g_usb_device_bulk_transfer (usb_device, + FASTBOOT_EP_OUT, + buf2, + buflen, + &actual_len, + FASTBOOT_TRANSACTION_TIMEOUT, + NULL, error); + if (!ret) { + g_prefix_error (error, "failed to do bulk transfer: "); + return FALSE; + } + if (actual_len != buflen) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_fastboot_device_writestr (FuDevice *device, const gchar *str, GError **error) +{ + gsize buflen = strlen (str); + if (buflen > FASTBOOT_CMD_BUFSZ - 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "fastboot limits writes to %i bytes", + FASTBOOT_CMD_BUFSZ - 4); + return FALSE; + } + return fu_fastboot_device_write (device, (const guint8 *) str, buflen, error); +} + +typedef enum { + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, +} FuFastbootDeviceReadFlags; + +static gboolean +fu_fastboot_device_read (FuDevice *device, + gchar **str, + FuFastbootDeviceReadFlags flags, + GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + guint retries = 1; + + /* these commands may return INFO or take some time to complete */ + if (flags & FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL) + retries = FASTBOOT_TRANSACTION_RETRY_MAX; + + for (guint i = 0; i < retries; i++) { + gboolean ret; + gsize actual_len = 0; + guint8 buf[FASTBOOT_CMD_BUFSZ] = { 0x00 }; + g_autofree gchar *tmp = NULL; + g_autoptr(GError) error_local = NULL; + + ret = g_usb_device_bulk_transfer (usb_device, + FASTBOOT_EP_IN, + buf, + sizeof(buf), + &actual_len, + FASTBOOT_TRANSACTION_TIMEOUT, + NULL, &error_local); + if (!ret) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_TIMED_OUT)) { + g_debug ("ignoring %s", error_local->message); + continue; + } + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to do bulk transfer: "); + return FALSE; + } + fu_fastboot_buffer_dump ("read", buf, actual_len); + if (actual_len < 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + /* info */ + tmp = g_strndup ((const gchar *) buf + 4, self->blocksz - 4); + if (memcmp (buf, "INFO", 4) == 0) { + if (g_strcmp0 (tmp, "erasing flash") == 0) + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + else if (g_strcmp0 (tmp, "writing flash") == 0) + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + else + g_debug ("INFO returned unknown: %s", tmp); + continue; + } + + /* success */ + if (memcmp (buf, "OKAY", 4) == 0 || memcmp (buf, "DATA", 4) == 0) { + if (str != NULL) + *str = g_steal_pointer (&tmp); + return TRUE; + } + + /* failure */ + if (memcmp (buf, "FAIL", 4) == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read response: %s", tmp); + return FALSE; + } + + /* unknown failure */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read response"); + return FALSE; + } + + /* we timed out a *lot* */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no response to read"); + return FALSE; +} + +static gboolean +fu_fastboot_device_getvar (FuDevice *device, const gchar *key, gchar **str, GError **error) +{ + g_autofree gchar *tmp = g_strdup_printf ("getvar:%s", key); + if (!fu_fastboot_device_writestr (device, tmp, error)) + return FALSE; + if (!fu_fastboot_device_read (device, str, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_cmd (FuDevice *device, const gchar *cmd, GError **error) +{ + if (!fu_fastboot_device_writestr (device, cmd, error)) + return FALSE; + if (!fu_fastboot_device_read (device, NULL, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_flash (FuDevice *device, + const gchar *partition, + GBytes *fw, + GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + gsize sz = g_bytes_get_size (fw); + g_autofree gchar *tmp = g_strdup_printf ("download:%08x", (guint) sz); + g_autoptr(GPtrArray) chunks = NULL; + + /* tell the client the size of data to expect */ + if (!fu_fastboot_device_writestr (device, tmp, error)) + return FALSE; + if (!fu_fastboot_device_read (device, NULL, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, error)) + return FALSE; + + /* send the data in chunks */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + self->blocksz); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_fastboot_device_write (device, chk->data, chk->data_sz, error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len * 2); + } + if (!fu_fastboot_device_read (device, NULL, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_setup (FuDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + g_autofree gchar *product = NULL; + g_autofree gchar *serialno = NULL; + g_autofree gchar *version = NULL; + g_autofree gchar *secure = NULL; + g_autofree gchar *version_bootloader = NULL; + + /* product */ + if (!fu_fastboot_device_getvar (device, "product", &product, error)) + return FALSE; + if (product != NULL && product[0] != '\0') { + g_autofree gchar *tmp = g_strdup_printf ("Fastboot %s", product); + fu_device_set_name (device, tmp); + } + + /* fastboot API version */ + if (!fu_fastboot_device_getvar (device, "version", &version, error)) + return FALSE; + if (version != NULL && version[0] != '\0') + g_debug ("fastboot version=%s", version); + + /* bootloader version */ + if (!fu_fastboot_device_getvar (device, "version-bootloader", &version_bootloader, error)) + return FALSE; + if (version_bootloader != NULL && version_bootloader[0] != '\0') + fu_device_set_version_bootloader (device, version_bootloader); + + /* serialno */ + if (!fu_fastboot_device_getvar (device, "serialno", &serialno, error)) + return FALSE; + if (serialno != NULL && serialno[0] != '\0') + fu_device_set_serial (device, serialno); + + /* secure */ + if (!fu_fastboot_device_getvar (device, "secure", &secure, error)) + return FALSE; + if (secure != NULL && secure[0] != '\0') + self->secure = TRUE; + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_qfil_part (FuDevice *device, + FuArchive *archive, + XbNode *part, + GError **error) +{ + GBytes *data; + const gchar *fn; + const gchar *partition; + + /* not all partitions have images */ + fn = xb_node_query_text (part, "img_name", NULL); + if (fn == NULL) + return TRUE; + + /* find filename */ + data = fu_archive_lookup_by_fn (archive, fn, error); + if (data == NULL) + return FALSE; + + /* get the partition name */ + partition = xb_node_query_text (part, "name", error); + if (partition == NULL) + return FALSE; + if (g_str_has_prefix (partition, "0:")) + partition += 2; + + /* flash the partition */ + return fu_fastboot_device_flash (device, partition, data, error); +} + +static gboolean +fu_fastboot_device_write_motorola_part (FuDevice *device, + FuArchive *archive, + XbNode *part, + GError **error) +{ + const gchar *op = xb_node_get_attr (part, "operation"); + + /* oem */ + if (g_strcmp0 (op, "oem") == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "OEM commands are not supported"); + return FALSE; + } + + /* getvar */ + if (g_strcmp0 (op, "getvar") == 0) { + const gchar *var = xb_node_get_attr (part, "var"); + g_autofree gchar *tmp = NULL; + + /* check required args */ + if (var == NULL) { + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required var for part: %s", tmp); + return FALSE; + } + + /* just has to be non-empty */ + if (!fu_fastboot_device_getvar (device, var, &tmp, error)) + return FALSE; + if (tmp == NULL || tmp[0] == '\0') { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to getvar %s", var); + return FALSE; + } + return TRUE; + } + + /* erase */ + if (g_strcmp0 (op, "erase") == 0) { + const gchar *partition = xb_node_get_attr (part, "partition"); + g_autofree gchar *cmd = g_strdup_printf ("erase:%s", partition); + + /* check required args */ + if (partition == NULL) { + g_autofree gchar *tmp = NULL; + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required partition for part: %s", tmp); + return FALSE; + } + + /* erase the partition */ + return fu_fastboot_device_cmd (device, cmd, error); + } + + /* flash */ + if (g_strcmp0 (op, "flash") == 0) { + GBytes *data; + const gchar *filename = xb_node_get_attr (part, "filename"); + const gchar *partition = xb_node_get_attr (part, "partition"); + struct { + GChecksumType kind; + const gchar *str; + } csum_kinds[] = { + { G_CHECKSUM_MD5, "MD5" }, + { G_CHECKSUM_SHA1, "SHA1" }, + { 0, NULL } + }; + + /* check required args */ + if (partition == NULL || filename == NULL) { + g_autofree gchar *tmp = NULL; + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required partition and filename: %s", tmp); + return FALSE; + } + + /* find filename */ + data = fu_archive_lookup_by_fn (archive, filename, error); + if (data == NULL) + return FALSE; + + /* checksum is optional */ + for (guint i = 0; csum_kinds[i].str != NULL; i++) { + const gchar *csum; + g_autofree gchar *csum_actual = NULL; + + /* not provided */ + csum = xb_node_get_attr (part, csum_kinds[i].str); + if (csum == NULL) + continue; + + /* check is valid */ + csum_actual = g_compute_checksum_for_bytes (csum_kinds[i].kind, data); + if (g_strcmp0 (csum, csum_actual) != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "%s invalid, expected %s, got %s", + filename, csum, csum_actual); + return FALSE; + } + } + + /* flash the partition */ + return fu_fastboot_device_flash (device, partition, data, error); + } + + /* dumb operation that doesn't expect a response */ + if (g_strcmp0 (op, "boot") == 0 || + g_strcmp0 (op, "continue") == 0 || + g_strcmp0 (op, "reboot") == 0 || + g_strcmp0 (op, "reboot-bootloader") == 0 || + g_strcmp0 (op, "powerdown") == 0) { + return fu_fastboot_device_cmd (device, op, error); + } + + /* unknown */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unknown operation %s", op); + return FALSE; +} + +static gboolean +fu_fastboot_device_write_motorola (FuDevice *device, + FuArchive* archive, + GError **error) +{ + GBytes *data; + g_autoptr(GPtrArray) parts = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; + + /* load the manifest of operations */ + data = fu_archive_lookup_by_fn (archive, "flashfile.xml", error); + if (data == NULL) + return FALSE; + if (!xb_builder_source_load_bytes (source, data, + XB_BUILDER_SOURCE_FLAG_NONE, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + + /* get all the operation parts */ + parts = xb_silo_query (silo, "parts/part", 0, error); + if (parts == NULL) + return FALSE; + for (guint i = 0; i < parts->len; i++) { + XbNode *part = g_ptr_array_index (parts, i); + if (!fu_fastboot_device_write_motorola_part (device, + archive, + part, + error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_qfil (FuDevice *device, FuArchive* archive, GError **error) +{ + GBytes *data; + g_autoptr(GPtrArray) parts = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; + + /* load the manifest of operations */ + data = fu_archive_lookup_by_fn (archive, "partition_nand.xml", error); + if (data == NULL) + return FALSE; + if (!xb_builder_source_load_bytes (source, data, + XB_BUILDER_SOURCE_FLAG_NONE, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + + /* get all the operation parts */ + parts = xb_silo_query (silo, "nandboot/partitions/partition", 0, error); + if (parts == NULL) + return FALSE; + for (guint i = 0; i < parts->len; i++) { + XbNode *part = g_ptr_array_index (parts, i); + if (!fu_fastboot_device_write_qfil_part (device, + archive, + part, + error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + g_autoptr(FuArchive) archive = NULL; + + /* decompress entire archive ahead of time */ + archive = fu_archive_new (fw, FU_ARCHIVE_FLAG_IGNORE_PATH, error); + if (archive == NULL) + return FALSE; + + /* load the manifest of operations */ + if (fu_archive_lookup_by_fn (archive, "partition_nand.xml", NULL) != NULL) + return fu_fastboot_device_write_qfil (device, archive, error); + if (fu_archive_lookup_by_fn (archive, "flashfile.xml", NULL) != NULL) { + return fu_fastboot_device_write_motorola (device, + archive, + error); + } + + /* not supported */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "manifest not supported"); + return FALSE; +} + +static gboolean +fu_fastboot_device_close (FuUsbDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* we're done here */ + if (!g_usb_device_release_interface (usb_device, self->intf_nr, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + + /* load slave address from quirks */ + if (g_strcmp0 (key, "FastbootBlockSize") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp >= 0x40 && tmp < 0x100000) { + self->blocksz = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid block size"); + return FALSE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; + +} + +static gboolean +fu_fastboot_device_attach (FuDevice *device, GError **error) +{ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + return fu_fastboot_device_cmd (device, "reboot", error); +} + +static void +fu_fastboot_device_init (FuFastbootDevice *self) +{ + /* this is a safe default, even using USBv1 */ + self->blocksz = 512; + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_remove_delay (FU_DEVICE (self), + FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_fastboot_device_class_init (FuFastbootDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->probe = fu_fastboot_device_probe; + klass_device->setup = fu_fastboot_device_setup; + klass_device->write_firmware = fu_fastboot_device_write_firmware; + klass_device->attach = fu_fastboot_device_attach; + klass_device->to_string = fu_fastboot_device_to_string; + klass_device->set_quirk_kv = fu_fastboot_device_set_quirk_kv; + klass_usb_device->open = fu_fastboot_device_open; + klass_usb_device->close = fu_fastboot_device_close; +} + +FuFastbootDevice * +fu_fastboot_device_new (FuUsbDevice *device) +{ + FuFastbootDevice *self = g_object_new (FU_TYPE_FASTBOOT_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff --git a/plugins/fastboot/fu-fastboot-device.h b/plugins/fastboot/fu-fastboot-device.h new file mode 100644 index 000000000..5f44c9167 --- /dev/null +++ b/plugins/fastboot/fu-fastboot-device.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_FASTBOOT_DEVICE_H +#define __FU_FASTBOOT_DEVICE_H + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_FASTBOOT_DEVICE (fu_fastboot_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuFastbootDevice, fu_fastboot_device, FU, FASTBOOT_DEVICE, FuUsbDevice) + +FuFastbootDevice *fu_fastboot_device_new (FuUsbDevice *device); + +G_END_DECLS + +#endif /* __FU_FASTBOOT_DEVICE_H */ diff --git a/plugins/fastboot/fu-plugin-fastboot.c b/plugins/fastboot/fu-plugin-fastboot.c new file mode 100644 index 000000000..694d1cddc --- /dev/null +++ b/plugins/fastboot/fu-plugin-fastboot.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-fastboot-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* reset */ + if (!fu_device_attach (device, error)) + return FALSE; + + /* wait for replug */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuFastbootDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + dev = fu_fastboot_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} diff --git a/plugins/fastboot/meson.build b/plugins/fastboot/meson.build new file mode 100644 index 000000000..4042e5310 --- /dev/null +++ b/plugins/fastboot/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginFastboot"'] + +install_data(['fastboot.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_fastboot', + sources : [ + 'fu-plugin-fastboot.c', + 'fu-fastboot-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index 4408d2f4c..7d84f63f5 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,6 +1,7 @@ subdir('dfu') subdir('colorhug') subdir('ebitdo') +subdir('fastboot') subdir('flashrom') subdir('steelseries') subdir('dell-dock') From d73fbe08ceec5b393a48fd4f8e8f7ddc5b508f9e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 3 Dec 2018 13:24:50 -0600 Subject: [PATCH 116/254] thunderbolt: Remove a superfluous boundary condition when verifying update `g_ascii_strtoull` returns 0 and sets `errno` to `-EINVAL` only when the base is invalid. It's hardcoded to `16` so this is impossible. Reading `-EINVAL` from `errno` is incorrect in these circumstances. Fixes: https://github.com/hughsie/fwupd/issues/879 --- plugins/thunderbolt/fu-plugin-thunderbolt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index 8316af9e0..c40791cd1 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -713,8 +713,7 @@ fu_plugin_update_attach (FuPlugin *plugin, return FALSE; } status = g_ascii_strtoull (attribute, NULL, 16); - if ((status == 0x00 && errno == EINVAL) || - (status == G_MAXUINT64 && errno == ERANGE)) { + if (status == G_MAXUINT64 && errno == ERANGE) { g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "failed to read 'nvm_authenticate: %s", From 8ec36ae826b493000ba25416a2d4fc9c5484bcf3 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 3 Dec 2018 16:06:45 -0600 Subject: [PATCH 117/254] trivial: dell-dock: reverse MST update order for I2C This mirrors the update process over DP aux to run the ESM update first. The thought process is as follows: The "version" displayed doesn't show ESM version, only standard bank version. So if the update fails for the ESM then because the update of the standard happening first it would never be flashed. --- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index 6f93c80a0..af332b048 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -771,7 +771,7 @@ fu_dell_dock_mst_write_fw (FuDevice *device, MSTBank bank_in_use = 0; guint retries = 2; gboolean checksum = FALSE; - guint8 order[3] = {Bank0, ESM}; + guint8 order[2] = {ESM, Bank0}; guint16 chip_id; const guint8* data = g_bytes_get_data (blob_fw, NULL); g_autofree gchar *dynamic_version = NULL; @@ -791,7 +791,7 @@ fu_dell_dock_mst_write_fw (FuDevice *device, return FALSE; if (bank_in_use == Bank0) - order[0] = Bank1; + order[1] = Bank1; /* enable remote control */ if (!fu_dell_dock_mst_enable_remote_control (self->symbiote, error)) From cc355beaf88351eccfd9ae3aaa757b7bd966a10f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 4 Dec 2018 15:35:18 -0600 Subject: [PATCH 118/254] trivial: Add a snap badge for fwupd --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6469d29c4..5fe4e5744 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ fwupd [![Build Status](https://travis-ci.org/hughsie/fwupd.png?branch=master)](https://travis-ci.org/hughsie/fwupd) [![Coverity Scan Build Status](https://scan.coverity.com/projects/10744/badge.svg)](https://scan.coverity.com/projects/10744) +[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-white.svg)](https://snapcraft.io/fwupd) + This project aims to make updating firmware on Linux automatic, safe and reliable. Additional information is available at the website: https://fwupd.org From 8949f3d0662090c8ca9ebbbb3ad6930428bf0d8f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 4 Dec 2018 09:17:42 +0000 Subject: [PATCH 119/254] wacom-usb: Remove the DTH generation hardware as it will not work with fwupd Fixes https://github.com/hughsie/fwupd/issues/882 --- plugins/wacom-usb/wacom-usb.quirk | 49 ------------------------------- 1 file changed, 49 deletions(-) diff --git a/plugins/wacom-usb/wacom-usb.quirk b/plugins/wacom-usb/wacom-usb.quirk index 8f937b313..33057e78a 100644 --- a/plugins/wacom-usb/wacom-usb.quirk +++ b/plugins/wacom-usb/wacom-usb.quirk @@ -1,22 +1,3 @@ -# MobileStudio Pro 13 (touch) [DTH-W1320] -[DeviceInstanceId=USB\VID_056A&PID_034A] -Plugin = wacom-usb -Flags = use-runtime-version - -# MobileStudio Pro 16 (touch) [DTH-W1620] -[DeviceInstanceId=USB\VID_056A&PID_034B] -Plugin = wacom-usb -Flags = use-runtime-version - -# MobileStudio Pro 13 (pen/pad) [DTH-W1320] -[DeviceInstanceId=USB\VID_056A&PID_034D] -Plugin = wacom-usb -Flags = use-runtime-version - -# MobileStudio Pro 16 (pen/pad) [DTH-W1620] -[DeviceInstanceId=USB\VID_056A&PID_034E] -Plugin = wacom-usb -Flags = use-runtime-version # Intuos Pro medium (2nd-gen BT) [PTH-660] [DeviceInstanceId=USB\VID_056A&PID_0360] @@ -38,26 +19,6 @@ Flags = use-runtime-version Plugin = wacom-usb Flags = use-runtime-version -# Cintiq Pro 13 (pen/pad) [DTH-1320] -[DeviceInstanceId=USB\VID_056A&PID_034F] -Plugin = wacom-usb -Flags = use-runtime-version - -# Cintiq Pro 16 (pen/pad) [DTH-1620] -[DeviceInstanceId=USB\VID_056A&PID_0350] -Plugin = wacom-usb -Flags = use-runtime-version - -# Cintiq Pro 13 (touch) [DTH-1320] -[DeviceInstanceId=USB\VID_056A&PID_0353] -Plugin = wacom-usb -Flags = use-runtime-version - -# Cintiq Pro 16 (touch) [DTH-1620] -[DeviceInstanceId=USB\VID_056A&PID_0354] -Plugin = wacom-usb -Flags = use-runtime-version - # Intuos Pro medium (2nd-gen USB) [PTH-660] [DeviceInstanceId=USB\VID_056A&PID_0357] Plugin = wacom-usb @@ -68,16 +29,6 @@ Flags = use-runtime-version Plugin = wacom-usb Flags = use-runtime-version -# Pen [DTH-1152] -[DeviceInstanceId=USB\VID_056A&PID_035A] -Plugin = wacom-usb -Flags = use-runtime-version - -# Touch [DTH-1152] -[DeviceInstanceId=USB\VID_056A&PID_0368] -Plugin = wacom-usb -Flags = use-runtime-version - # Intuos S 3rd-gen (USB) [CTL-4100] [DeviceInstanceId=USB\VID_056A&PID_0374] Plugin = wacom-usb From 55b8a249e0bf6850d6bcaf3243d489a203f0d71d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 5 Dec 2018 10:59:07 +0000 Subject: [PATCH 120/254] Sanitize the version if the version format has been specified This converts versions like 'v1.2.3' into a valid semver of '1.2.3' if the version format has been set. Fixes https://github.com/hughsie/fwupd/issues/884 --- src/fu-device.c | 31 +++++++++++++++++++++++++++++-- src/fu-self-test.c | 10 ++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/fu-device.c b/src/fu-device.c index 5059c0b7c..1a30b9a56 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -1071,6 +1071,16 @@ fu_device_set_id (FuDevice *self, const gchar *id) fwupd_device_set_id (FWUPD_DEVICE (self), id_hash); } +static gboolean +fu_device_is_valid_semver_char (gchar c) +{ + if (g_ascii_isdigit (c)) + return TRUE; + if (c == '.') + return TRUE; + return FALSE; +} + /** * fu_device_set_version: * @self: A #FuDevice @@ -1084,14 +1094,31 @@ void fu_device_set_version (FuDevice *self, const gchar *version) { FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GString) version_safe = NULL; g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (version != NULL); + /* sanitize if required */ + if (priv->version_format != FU_VERSION_FORMAT_UNKNOWN && + priv->version_format != FU_VERSION_FORMAT_PLAIN) { + version_safe = g_string_new (NULL); + for (guint i = 0; version[i] != '\0'; i++) { + if (fu_device_is_valid_semver_char (version[i])) + g_string_append_c (version_safe, version[i]); + } + if (g_strcmp0 (version, version_safe->str) != 0) { + g_debug ("converted '%s' to '%s'", + version, version_safe->str); + } + } else { + version_safe = g_string_new (version); + } + /* try to autodetect the version-format */ if (priv->version_format == FU_VERSION_FORMAT_UNKNOWN) - priv->version_format = fu_common_version_guess_format (version); - fwupd_device_set_version (FWUPD_DEVICE (self), version); + priv->version_format = fu_common_version_guess_format (version_safe->str); + fwupd_device_set_version (FWUPD_DEVICE (self), version_safe->str); } /** diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 5b7fd5a36..fc3e828a2 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -1458,6 +1458,15 @@ fu_device_list_func (void) "1a8d0d9a96ad3e67ba76cf3033623625dc6d6882"); } +static void +fu_device_version_format_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + fu_device_set_version_format (device, FU_VERSION_FORMAT_TRIPLET); + fu_device_set_version (device, "Ver1.2.3 RELEASE"); + g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3"); +} + static void fu_device_open_refcount_func (void) { @@ -3255,6 +3264,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/device-locker{fail}", fu_device_locker_fail_func); g_test_add_func ("/fwupd/device{metadata}", fu_device_metadata_func); g_test_add_func ("/fwupd/device{open-refcount}", fu_device_open_refcount_func); + g_test_add_func ("/fwupd/device{version-format}", fu_device_version_format_func); g_test_add_func ("/fwupd/device-list", fu_device_list_func); g_test_add_func ("/fwupd/device-list{delay}", fu_device_list_delay_func); g_test_add_func ("/fwupd/device-list{compatible}", fu_device_list_compatible_func); From e59cb9af012a13945ccce391b3f12a765716527c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 5 Dec 2018 14:37:40 +0000 Subject: [PATCH 121/254] trivial: Add fu_common_dump_raw() --- plugins/colorhug/fu-colorhug-common.c | 14 ------- plugins/colorhug/fu-colorhug-common.h | 3 -- plugins/colorhug/fu-colorhug-device.c | 6 ++- plugins/csr/fu-csr-device.c | 26 +++++------- plugins/ebitdo/fu-ebitdo-common.c | 14 ------- plugins/ebitdo/fu-ebitdo-common.h | 3 -- plugins/ebitdo/fu-ebitdo-device.c | 4 +- plugins/unifying/fu-unifying-bootloader.c | 15 +++++-- plugins/unifying/fu-unifying-common.c | 20 --------- plugins/unifying/fu-unifying-common.h | 4 -- plugins/unifying/fu-unifying-hidpp.c | 7 +++- src/fu-common.c | 50 +++++++++++++++++++++++ src/fu-common.h | 7 ++++ 13 files changed, 90 insertions(+), 83 deletions(-) diff --git a/plugins/colorhug/fu-colorhug-common.c b/plugins/colorhug/fu-colorhug-common.c index 6bb9b3801..b0773c758 100644 --- a/plugins/colorhug/fu-colorhug-common.c +++ b/plugins/colorhug/fu-colorhug-common.c @@ -85,17 +85,3 @@ ch_strerror (ChError error_enum) return "Self test failed: EEPROM"; return NULL; } - -void -ch_buffer_dump (const gchar *title, const guint8 *buf, gsize sz) -{ - if (g_getenv ("FWUPD_COLORHUG_VERBOSE") == NULL) - return; - g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); - for (gsize i = 0; i < sz; i++) { - g_print ("%02x ", buf[i]); - if (i > 0 && (i + 1) % 256 == 0) - g_print ("\n"); - } - g_print ("\n"); -} diff --git a/plugins/colorhug/fu-colorhug-common.h b/plugins/colorhug/fu-colorhug-common.h index e0cfbf936..e0b2fb9e4 100644 --- a/plugins/colorhug/fu-colorhug-common.h +++ b/plugins/colorhug/fu-colorhug-common.h @@ -52,9 +52,6 @@ typedef enum { } ChError; const gchar *ch_strerror (ChError error_enum); -void ch_buffer_dump (const gchar *title, - const guint8 *buf, - gsize sz); G_END_DECLS diff --git a/plugins/colorhug/fu-colorhug-device.c b/plugins/colorhug/fu-colorhug-device.c index 976ef0e30..7c6922f35 100644 --- a/plugins/colorhug/fu-colorhug-device.c +++ b/plugins/colorhug/fu-colorhug-device.c @@ -82,7 +82,8 @@ fu_colorhug_device_msg (FuColorhugDevice *self, guint8 cmd, memcpy (buf + 1, ibuf, ibufsz); /* request */ - ch_buffer_dump ("REQ", buf, ibufsz + 1); + if (g_getenv ("FWUPD_COLORHUG_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "REQ", buf, ibufsz + 1); if (!g_usb_device_interrupt_transfer (usb_device, CH_USB_HID_EP_OUT, buf, @@ -115,7 +116,8 @@ fu_colorhug_device_msg (FuColorhugDevice *self, guint8 cmd, g_prefix_error (error, "failed to get reply: "); return FALSE; } - ch_buffer_dump ("RES", buf, actual_length); + if (g_getenv ("FWUPD_COLORHUG_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "RES", buf, actual_length); /* old bootloaders do not return the full block */ if (actual_length != CH_USB_HID_EP_SIZE && diff --git a/plugins/csr/fu-csr-device.c b/plugins/csr/fu-csr-device.c index eacb8167b..536665545 100644 --- a/plugins/csr/fu-csr-device.c +++ b/plugins/csr/fu-csr-device.c @@ -67,17 +67,6 @@ fu_csr_device_to_string (FuDevice *device, GString *str) g_string_append_printf (str, " timeout:\t\t%" G_GUINT32_FORMAT "\n", self->dnload_timeout); } -static void -fu_csr_device_dump (const gchar *title, const guint8 *buf, gsize sz) -{ - if (g_getenv ("FWUPD_CSR_VERBOSE") == NULL) - return; - g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); - for (gsize i = 0; i < sz; i++) - g_print ("%02x ", buf[i]); - g_print ("\n"); -} - static gboolean fu_csr_device_attach (FuDevice *device, GError **error) { @@ -86,7 +75,8 @@ fu_csr_device_attach (FuDevice *device, GError **error) gsize sz = 0; guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, FU_CSR_CONTROL_RESET }; - fu_csr_device_dump ("Reset", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Reset", buf, sz); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, @@ -135,7 +125,8 @@ fu_csr_device_get_status (FuCsrDevice *self, GError **error) g_prefix_error (error, "Failed to GetStatus: "); return FALSE; } - fu_csr_device_dump ("GetStatus", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "GetStatus", buf, sz); /* check packet */ if (sz != FU_CSR_STATUS_HEADER_SIZE) { @@ -179,7 +170,8 @@ fu_csr_device_clear_status (FuCsrDevice *self, GError **error) return TRUE; /* hit hardware */ - fu_csr_device_dump ("ClearStatus", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "ClearStatus", buf, sz); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, @@ -230,7 +222,8 @@ fu_csr_device_upload_chunk (FuCsrDevice *self, GError **error) g_prefix_error (error, "Failed to ReadFirmware: "); return NULL; } - fu_csr_device_dump ("ReadFirmware", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "ReadFirmware", buf, sz); /* too small to parse */ if (sz < FU_CSR_COMMAND_HEADER_SIZE) { @@ -362,7 +355,8 @@ fu_csr_device_download_chunk (FuCsrDevice *self, guint16 idx, GBytes *chunk, GEr memcpy (buf + FU_CSR_COMMAND_HEADER_SIZE, chunk_data, chunk_sz); /* hit hardware */ - fu_csr_device_dump ("Upgrade", buf, sizeof(buf)); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Upgrade", buf, sizeof(buf)); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, diff --git a/plugins/ebitdo/fu-ebitdo-common.c b/plugins/ebitdo/fu-ebitdo-common.c index 0934f960d..2738931ed 100644 --- a/plugins/ebitdo/fu-ebitdo-common.c +++ b/plugins/ebitdo/fu-ebitdo-common.c @@ -64,20 +64,6 @@ fu_ebitdo_pkt_cmd_to_string (FuEbitdoPktCmd cmd) return NULL; } -void -fu_ebitdo_dump_raw (const gchar *title, const guint8 *data, gsize len) -{ - g_print ("%s:", title); - for (gsize i = strlen (title); i < 16; i++) - g_print (" "); - for (gsize i = 0; i < len; i++) { - g_print ("%02x ", data[i]); - if (i > 0 && i % 32 == 0) - g_print ("\n"); - } - g_print ("\n"); -} - void fu_ebitdo_dump_pkt (FuEbitdoPkt *hdr) { diff --git a/plugins/ebitdo/fu-ebitdo-common.h b/plugins/ebitdo/fu-ebitdo-common.h index db8cf0c5b..84f2e5248 100644 --- a/plugins/ebitdo/fu-ebitdo-common.h +++ b/plugins/ebitdo/fu-ebitdo-common.h @@ -70,8 +70,5 @@ const gchar *fu_ebitdo_pkt_cmd_to_string (FuEbitdoPktCmd cmd); const gchar *fu_ebitdo_pkt_type_to_string (FuEbitdoPktType type); void fu_ebitdo_dump_firmware_header (FuEbitdoFirmwareHeader *hdr); void fu_ebitdo_dump_pkt (FuEbitdoPkt *hdr); -void fu_ebitdo_dump_raw (const gchar *title, - const guint8 *data, - gsize len); #endif /* __FU_EBITDO_COMMON_H */ diff --git a/plugins/ebitdo/fu-ebitdo-device.c b/plugins/ebitdo/fu-ebitdo-device.c index 334f105ae..25e1ddd8e 100644 --- a/plugins/ebitdo/fu-ebitdo-device.c +++ b/plugins/ebitdo/fu-ebitdo-device.c @@ -66,7 +66,7 @@ fu_ebitdo_device_send (FuEbitdoDevice *self, /* debug */ if (g_getenv ("FWUPD_EBITDO_VERBOSE") != NULL) { - fu_ebitdo_dump_raw ("->DEVICE", packet, (gsize) hdr->pkt_len + 1); + fu_common_dump_raw (G_LOG_DOMAIN, "->DEVICE", packet, (gsize) hdr->pkt_len + 1); fu_ebitdo_dump_pkt (hdr); } @@ -127,7 +127,7 @@ fu_ebitdo_device_receive (FuEbitdoDevice *self, /* debug */ if (g_getenv ("FWUPD_EBITDO_VERBOSE") != NULL) { - fu_ebitdo_dump_raw ("<-DEVICE", packet, actual_length); + fu_common_dump_raw (G_LOG_DOMAIN, "<-DEVICE", packet, actual_length); fu_ebitdo_dump_pkt (hdr); } diff --git a/plugins/unifying/fu-unifying-bootloader.c b/plugins/unifying/fu-unifying-bootloader.c index 3ffffe700..3e148d8c2 100644 --- a/plugins/unifying/fu-unifying-bootloader.c +++ b/plugins/unifying/fu-unifying-bootloader.c @@ -299,7 +299,10 @@ fu_unifying_bootloader_request (FuUnifyingBootloader *self, memcpy (buf_request + 0x04, req->data, 28); /* send request */ - fu_unifying_dump_raw ("host->device", buf_request, sizeof (buf_request)); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "host->device", + buf_request, sizeof (buf_request)); + } if (usb_device != NULL) { if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, @@ -332,7 +335,10 @@ fu_unifying_bootloader_request (FuUnifyingBootloader *self, &error_ignore)) { g_debug ("ignoring: %s", error_ignore->message); } else { - fu_unifying_dump_raw ("device->host", buf_response, actual_length); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", + buf_response, actual_length); + } } return TRUE; } @@ -365,7 +371,10 @@ fu_unifying_bootloader_request (FuUnifyingBootloader *self, } actual_length = sizeof (buf_response); } - fu_unifying_dump_raw ("device->host", buf_response, actual_length); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", + buf_response, actual_length); + } /* parse response */ if ((buf_response[0x00] & 0xf0) != req->cmd) { diff --git a/plugins/unifying/fu-unifying-common.c b/plugins/unifying/fu-unifying-common.c index 75e28ba77..be67b59be 100644 --- a/plugins/unifying/fu-unifying-common.c +++ b/plugins/unifying/fu-unifying-common.c @@ -33,26 +33,6 @@ fu_unifying_buffer_read_uint16 (const gchar *str) return tmp; } -void -fu_unifying_dump_raw (const gchar *title, const guint8 *data, gsize len) -{ - g_autoptr(GString) str = g_string_new (NULL); - if (len == 0) - return; - if (g_getenv ("FWUPD_UNIFYING_VERBOSE") == NULL) - return; - - g_string_append_printf (str, "%s:", title); - for (gsize i = strlen (title); i < 16; i++) - g_string_append (str, " "); - for (gsize i = 0; i < len; i++) { - g_string_append_printf (str, "%02x ", data[i]); - if (i > 0 && i % 32 == 0) - g_string_append (str, "\n"); - } - g_debug ("%s", str->str); -} - gchar * fu_unifying_format_version (const gchar *name, guint8 major, guint8 minor, guint16 build) { diff --git a/plugins/unifying/fu-unifying-common.h b/plugins/unifying/fu-unifying-common.h index 3e07178b8..6343c386a 100644 --- a/plugins/unifying/fu-unifying-common.h +++ b/plugins/unifying/fu-unifying-common.h @@ -22,10 +22,6 @@ G_BEGIN_DECLS /* Signed firmware are very long to verify on the device */ #define FU_UNIFYING_DEVICE_TIMEOUT_MS 20000 -void fu_unifying_dump_raw (const gchar *title, - const guint8 *data, - gsize len); - guint8 fu_unifying_buffer_read_uint8 (const gchar *str); guint16 fu_unifying_buffer_read_uint16 (const gchar *str); diff --git a/plugins/unifying/fu-unifying-hidpp.c b/plugins/unifying/fu-unifying-hidpp.c index d397d37cb..6240d3bfd 100644 --- a/plugins/unifying/fu-unifying-hidpp.c +++ b/plugins/unifying/fu-unifying-hidpp.c @@ -6,6 +6,7 @@ #include "config.h" +#include "fu-common.h" #include "fu-unifying-common.h" #include "fu-unifying-hidpp.h" @@ -69,7 +70,8 @@ fu_unifying_hidpp_send (gint fd, if (msg->hidpp_version >= 2.f) msg->function_id |= FU_UNIFYING_HIDPP_MSG_SW_ID; - fu_unifying_dump_raw ("host->device", (guint8 *) msg, len); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "host->device", (guint8 *) msg, len); /* detailed debugging */ if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { @@ -108,7 +110,8 @@ fu_unifying_hidpp_receive (gint fd, } /* check long enough, but allow returning oversize packets */ - fu_unifying_dump_raw ("device->host", (guint8 *) msg, read_size); + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", (guint8 *) msg, read_size); if (read_size < fu_unifying_hidpp_msg_get_payload_length (msg)) { g_set_error (error, G_IO_ERROR, diff --git a/src/fu-common.c b/src/fu-common.c index 37d74953f..e7117e30e 100644 --- a/src/fu-common.c +++ b/src/fu-common.c @@ -1058,3 +1058,53 @@ fu_common_string_replace (GString *string, const gchar *search, const gchar *rep return count; } + +/** + * fu_common_dump_raw: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @data: buffer to print + * @len: the size of @data + * + * Dumps a raw buffer to the screen. + * + * Since: 1.2.2 + **/ +void +fu_common_dump_raw (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len) +{ + g_autoptr(GString) str = g_string_new (NULL); + if (title != NULL) + g_string_append_printf (str, "%s:", title); + for (gsize i = str->len; i < 16; i++) + g_string_append (str, " "); + for (gsize i = 0; i < len; i++) { + g_string_append_printf (str, "%02x ", data[i]); + if (i > 0 && i % 32 == 0) + g_string_append (str, "\n"); + } + g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", str->str); +} + +/** + * fu_common_dump_raw: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @bytes: a #GBytes + * + * Dumps a byte buffer to the screen. + * + * Since: 1.2.2 + **/ +void +fu_common_dump_bytes (const gchar *log_domain, + const gchar *title, + GBytes *bytes) +{ + gsize len = 0; + const guint8 *data = g_bytes_get_data (bytes, &len); + fu_common_dump_raw (log_domain, title, data, len); +} diff --git a/src/fu-common.h b/src/fu-common.h index a14802a10..69b0a88f5 100644 --- a/src/fu-common.h +++ b/src/fu-common.h @@ -65,6 +65,13 @@ guint64 fu_common_strtoull (const gchar *str); gchar *fu_common_find_program_in_path (const gchar *basename, GError **error); gchar *fu_common_strstrip (const gchar *str); +void fu_common_dump_raw (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len); +void fu_common_dump_bytes (const gchar *log_domain, + const gchar *title, + GBytes *bytes); typedef guint FuEndianType; From 3561d9bef9124148fde7648fe6b6d84a841b8b02 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 5 Dec 2018 17:28:41 -0600 Subject: [PATCH 122/254] trivial: snap: move to efivar 37 --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 51bc5f39f..50512dd27 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -33,7 +33,7 @@ parts: make-parameters: - prefix=/ - libdir=/lib - source: https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2 + source: https://github.com/rhboot/efivar/releases/download/37/efivar-37.tar.bz2 build-packages: - libpopt-dev prime: From d583bafb6f56d67af58f373b11484a4026310bef Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 23 Nov 2018 13:57:22 +0000 Subject: [PATCH 123/254] Only run attach and detach if the device is in the wrong mode --- src/fu-engine.c | 90 ++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 9c61bbb7c..ef284be4f 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1385,6 +1385,38 @@ fu_engine_get_plugins (FuEngine *self) return fu_plugin_list_get_all (self->plugin_list); } +static FuDevice * +fu_engine_get_device_by_id (FuEngine *self, const gchar *device_id, GError **error) +{ + g_autoptr(FuDevice) device1 = NULL; + g_autoptr(FuDevice) device2 = NULL; + + /* find device */ + device1 = fu_device_list_get_by_id (self->device_list, device_id, error); + if (device1 == NULL) + return NULL; + + /* no replug required */ + if (!fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) + return g_steal_pointer (&device1); + + /* wait for device to disconnect and reconnect */ + if (!fu_device_list_wait_for_replug (self->device_list, device1, error)) { + g_prefix_error (error, "failed to wait for detach replug: "); + return NULL; + } + + /* get the new device */ + device2 = fu_device_list_get_by_id (self->device_list, device_id, error); + if (device2 == NULL) { + g_prefix_error (error, "failed to get device after replug: "); + return NULL; + } + + /* success */ + return g_steal_pointer (&device2); +} + gboolean fu_engine_install_blob (FuEngine *self, FuDevice *device_orig, @@ -1451,21 +1483,9 @@ fu_engine_install_blob (FuEngine *self, /* in case another device caused us to go into replug before starting */ g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach: "); + device = fu_engine_get_device_by_id (self, device_id_orig, error); + if (device == NULL) return FALSE; - } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for detach replug: "); - return FALSE; - } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach replug: "); - return FALSE; - } /* mark this as modified even if we actually fail to do the update */ fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); @@ -1519,19 +1539,9 @@ fu_engine_install_blob (FuEngine *self, return FALSE; } g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); + device = fu_engine_get_device_by_id (self, device_id_orig, error); if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach: "); - return FALSE; - } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for detach replug: "); - return FALSE; - } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after detach replug: "); + g_prefix_error (error, "failed to get device after detach: "); return FALSE; } if (!fu_plugin_runner_update (plugin, @@ -1576,19 +1586,9 @@ fu_engine_install_blob (FuEngine *self, return FALSE; } g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); + device = fu_engine_get_device_by_id (self, device_id_orig, error); if (device == NULL) { - g_prefix_error (error, "failed to get device ID after update: "); - return FALSE; - } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for replug after update: "); - return FALSE; - } - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after post-update restart: "); + g_prefix_error (error, "failed to get device after update: "); return FALSE; } if (!fu_plugin_runner_update_attach (plugin, device, &error_local)) { @@ -1605,23 +1605,13 @@ fu_engine_install_blob (FuEngine *self, return FALSE; } g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); + device = fu_engine_get_device_by_id (self, device_id_orig, error); if (device == NULL) { - g_prefix_error (error, "failed to get device ID after attach: "); - return FALSE; - } - if (!fu_device_list_wait_for_replug (self->device_list, device, error)) { - g_prefix_error (error, "failed to wait for replug after attach: "); + g_prefix_error (error, "failed to get device after attach: "); return FALSE; } /* get the new version number */ - g_clear_object (&device); - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) { - g_prefix_error (error, "failed to get device ID after attach replug: "); - return FALSE; - } if (!fu_plugin_runner_update_reload (plugin, device, error)) { g_prefix_error (error, "failed to reload device: "); return FALSE; From bccaaf5194fbcd5f08001f4ba280b9974ad60383 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 5 Dec 2018 14:46:13 +0000 Subject: [PATCH 124/254] Add shared functionality for reading and writing with O_NONBLOCK Two plugins have very similar code already, and we're about to get another. --- plugins/altos/fu-altos-device.c | 172 ++------- plugins/unifying/fu-unifying-common.c | 149 -------- plugins/unifying/fu-unifying-common.h | 13 - plugins/unifying/fu-unifying-hidpp.c | 37 +- plugins/unifying/fu-unifying-hidpp.h | 8 +- plugins/unifying/fu-unifying-peripheral.c | 47 ++- plugins/unifying/fu-unifying-runtime.c | 26 +- src/fu-io-channel.c | 437 ++++++++++++++++++++++ src/fu-io-channel.h | 69 ++++ src/meson.build | 5 + 10 files changed, 586 insertions(+), 377 deletions(-) create mode 100644 src/fu-io-channel.c create mode 100644 src/fu-io-channel.h diff --git a/plugins/altos/fu-altos-device.c b/plugins/altos/fu-altos-device.c index 56bbc7a25..9087751c8 100644 --- a/plugins/altos/fu-altos-device.c +++ b/plugins/altos/fu-altos-device.c @@ -12,6 +12,7 @@ #include #include +#include "fu-io-channel.h" #include "fu-altos-device.h" #include "fu-altos-firmware.h" @@ -25,7 +26,7 @@ struct _FuAltosDevice { guint64 addr_base; guint64 addr_bound; struct termios tty_termios; - gint tty_fd; + FuIOChannel *io_channel; }; G_DEFINE_TYPE (FuAltosDevice, fu_altos_device, FU_TYPE_USB_DEVICE) @@ -149,60 +150,15 @@ fu_altos_device_tty_write (FuAltosDevice *self, gssize data_len, GError **error) { - gint rc; - gssize idx = 0; - guint timeout_ms = 500; - struct pollfd fds; - /* lets assume this is text */ if (data_len < 0) data_len = strlen (data); - - fds.fd = self->tty_fd; - fds.events = POLLOUT; - - g_debug ("write, with timeout %ums", timeout_ms); - while (idx < data_len) { - - /* wait for data to be allowed to write without blocking */ - rc = poll (&fds, 1, (gint) timeout_ms); - if (rc == 0) - break; - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to poll %i", - self->tty_fd); - return FALSE; - } - - /* we can write data */ - if (fds.revents & POLLOUT) { - gssize len; - g_debug ("writing %" G_GSSIZE_FORMAT " bytes: %s", data_len, data); - len = write (self->tty_fd, data + idx, data_len - idx); - if (len < 0) { - if (errno == EAGAIN) { - g_debug ("got EAGAIN, trying harder"); - continue; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "failed to write %" G_GSSIZE_FORMAT - " bytes to %i: %s" , - data_len, - self->tty_fd, - strerror (errno)); - return FALSE; - } - g_debug ("wrote %" G_GSSIZE_FORMAT " bytes", len); - idx += len; - } - } - - return TRUE; + return fu_io_channel_write_raw (self->io_channel, + (const guint8 *) data, + (gsize) data_len, + 500, /* ms */ + FU_IO_CHANNEL_FLAG_NONE, + error); } static GString * @@ -211,90 +167,12 @@ fu_altos_device_tty_read (FuAltosDevice *self, gssize max_size, GError **error) { - gint rc; - struct pollfd fds; - g_autoptr(GString) str = g_string_new (NULL); - - fds.fd = self->tty_fd; - fds.events = POLLIN; - - g_debug ("read, with timeout %ums", timeout_ms); - for (;;) { - /* wait for data to appear */ - rc = poll (&fds, 1, (gint) timeout_ms); - if (rc == 0) - break; - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to poll %i", - self->tty_fd); - return NULL; - } - - /* we have data to read */ - if (fds.revents & POLLIN) { - guint8 buf[1024]; - gssize len = read (self->tty_fd, buf, sizeof (buf)); - if (len < 0) { - if (errno == EAGAIN) { - g_debug ("got EAGAIN, trying harder"); - continue; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to read %i: %s", - self->tty_fd, - strerror (errno)); - return NULL; - } - if (len > 0) { - g_debug ("read %" G_GSSIZE_FORMAT " bytes from device", len); - g_string_append_len (str, (gchar *) buf, len); - } - - /* check maximum size */ - if (max_size > 0 && str->len >= (guint) max_size) - break; - continue; - } - if (fds.revents & POLLERR) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "error condition"); - return NULL; - } - if (fds.revents & POLLHUP) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "connection hung up"); - return NULL; - } - if (fds.revents & POLLNVAL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "invalid request"); - return NULL; - } - } - - /* no data */ - if (str->len == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "no data received from device in %ums", - timeout_ms); + g_autoptr(GBytes) buf = NULL; + buf = fu_io_channel_read_bytes (self->io_channel, max_size, + timeout_ms, FU_IO_CHANNEL_FLAG_NONE, error); + if (buf == NULL) return NULL; - } - - /* return blob */ - return g_steal_pointer (&str); + return g_string_new_len (g_bytes_get_data (buf, NULL), g_bytes_get_size (buf)); } static gboolean @@ -304,18 +182,12 @@ fu_altos_device_tty_open (FuAltosDevice *self, GError **error) g_autoptr(GString) str = NULL; /* open device */ - self->tty_fd = open (self->tty, O_RDWR | O_NONBLOCK); - if (self->tty_fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - self->tty); + self->io_channel = fu_io_channel_new_file (self->tty, error); + if (self->io_channel == NULL) return FALSE; - } /* get the old termios settings so we can restore later */ - if (tcgetattr (self->tty_fd, &termios) < 0) { + if (tcgetattr (fu_io_channel_unix_get_fd (self->io_channel), &termios) < 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -340,7 +212,8 @@ fu_altos_device_tty_open (FuAltosDevice *self, GError **error) termios.c_cc[VTIME] = 0; /* set all new data */ - if (tcsetattr (self->tty_fd, TCSAFLUSH, &termios) < 0) { + if (tcsetattr (fu_io_channel_unix_get_fd (self->io_channel), + TCSAFLUSH, &termios) < 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -359,10 +232,11 @@ fu_altos_device_tty_open (FuAltosDevice *self, GError **error) static gboolean fu_altos_device_tty_close (FuAltosDevice *self, GError **error) { - - tcsetattr (self->tty_fd, TCSAFLUSH, &self->tty_termios); - close (self->tty_fd); - + tcsetattr (fu_io_channel_unix_get_fd (self->io_channel), + TCSAFLUSH, &self->tty_termios); + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); return TRUE; } diff --git a/plugins/unifying/fu-unifying-common.c b/plugins/unifying/fu-unifying-common.c index be67b59be..b25b4ca2f 100644 --- a/plugins/unifying/fu-unifying-common.c +++ b/plugins/unifying/fu-unifying-common.c @@ -45,152 +45,3 @@ fu_unifying_format_version (const gchar *name, guint8 major, guint8 minor, guint g_string_append_printf (str, "%02x.%02x_B%04x", major, minor, build); return g_string_free (str, FALSE); } - -static gboolean -fu_unifying_nonblock_flush (gint fd, GError **error) -{ - GPollFD poll[] = { - { - .fd = fd, - .events = G_IO_IN | G_IO_OUT | G_IO_ERR, - }, - }; - while (g_poll (poll, G_N_ELEMENTS(poll), 0) > 0) { - gchar c; - gint r = read (fd, &c, 1); - if (r < 0 && errno != EINTR) - break; - } - return TRUE; -} - -gboolean -fu_unifying_nonblock_write (gint fd, - const guint8 *data, - gsize data_sz, - GError **error) -{ - gssize wrote; - - /* sanity check */ - if (fd == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write: fd is not open"); - return FALSE; - } - - /* flush pending reads */ - if (!fu_unifying_nonblock_flush (fd, error)) - return FALSE; - - /* write */ - wrote = write (fd, data, data_sz); - if (wrote != (gssize) data_sz) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write: " - "wrote %" G_GSSIZE_FORMAT " of %" G_GSIZE_FORMAT, - wrote, data_sz); - return FALSE; - } - return TRUE; -} - -gboolean -fu_unifying_nonblock_read (gint fd, - guint8 *data, - gsize data_sz, - gsize *data_len, - guint timeout, - GError **error) -{ - gssize len = 0; - gint64 ts_start; - GPollFD poll[] = { - { - .fd = fd, - .events = G_IO_IN | G_IO_OUT | G_IO_ERR, - }, - }; - - /* sanity check */ - if (fd == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read: fd is not open"); - return FALSE; - } - - /* do a read with a timeout */ - ts_start = g_get_monotonic_time (); - while (1) { - gint rc; - gint ts_remain = ((g_get_monotonic_time () - ts_start) / 1000) + timeout; - if (ts_remain <= 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT, - "timeout already passed"); - return FALSE; - } - - /* waits for the fd to become ready */ - rc = g_poll (poll, G_N_ELEMENTS (poll), ts_remain); - if (rc < 0) { - if (errno == EINTR) - continue; - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "read interrupted: %s", - g_strerror (errno)); - return FALSE; - } else if (rc == 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT, - "timeout"); - return FALSE; - } - - /* read data from fd */ - len = read (fd, data, data_sz); - if (len <= 0) { - if (len == -1 && errno == EINTR) - continue; - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read data: %s", - g_strerror (errno)); - return FALSE; - } - - /* success */ - break; - }; - - /* success */ - if (data_len != NULL) - *data_len = (gsize) len; - return TRUE; -} - -gint -fu_unifying_nonblock_open (const gchar *filename, GError **error) -{ - gint fd; - fd = open (filename, O_RDWR | O_NONBLOCK); - if (fd < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to open %s", filename); - return -1; - } - return fd; -} diff --git a/plugins/unifying/fu-unifying-common.h b/plugins/unifying/fu-unifying-common.h index 6343c386a..a4f898863 100644 --- a/plugins/unifying/fu-unifying-common.h +++ b/plugins/unifying/fu-unifying-common.h @@ -30,19 +30,6 @@ gchar *fu_unifying_format_version (const gchar *name, guint8 minor, guint16 build); -gint fu_unifying_nonblock_open (const gchar *filename, - GError **error); -gboolean fu_unifying_nonblock_read (gint fd, - guint8 *data, - gsize data_sz, - gsize *data_len, - guint timeout, - GError **error); -gboolean fu_unifying_nonblock_write (gint fd, - const guint8 *data, - gsize data_sz, - GError **error); - G_END_DECLS #endif /* __FU_UNIFYING_COMMON_H */ diff --git a/plugins/unifying/fu-unifying-hidpp.c b/plugins/unifying/fu-unifying-hidpp.c index 6240d3bfd..cf9213480 100644 --- a/plugins/unifying/fu-unifying-hidpp.c +++ b/plugins/unifying/fu-unifying-hidpp.c @@ -57,30 +57,28 @@ fu_unifying_hidpp_msg_to_string (FuUnifyingHidppMsg *msg) } gboolean -fu_unifying_hidpp_send (gint fd, +fu_unifying_hidpp_send (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, guint timeout, GError **error) { gsize len = fu_unifying_hidpp_msg_get_payload_length (msg); - g_return_val_if_fail (fd > 0, FALSE); - /* only for HID++2.0 */ if (msg->hidpp_version >= 2.f) msg->function_id |= FU_UNIFYING_HIDPP_MSG_SW_ID; - if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) - fu_common_dump_raw (G_LOG_DOMAIN, "host->device", (guint8 *) msg, len); - /* detailed debugging */ if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { g_autofree gchar *str = fu_unifying_hidpp_msg_to_string (msg); + fu_common_dump_raw (G_LOG_DOMAIN, "host->device", (guint8 *) msg, len); g_print ("%s", str); } /* HID */ - if (!fu_unifying_nonblock_write (fd, (guint8 *) msg, len, error)) { + if (!fu_io_channel_write_raw (io_channel, (guint8 *) msg, len, 1500, + FU_IO_CHANNEL_FLAG_FLUSH_INPUT | + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, error)) { g_prefix_error (error, "failed to send: "); return FALSE; } @@ -90,21 +88,20 @@ fu_unifying_hidpp_send (gint fd, } gboolean -fu_unifying_hidpp_receive (gint fd, +fu_unifying_hidpp_receive (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, guint timeout, GError **error) { gsize read_size = 0; - g_return_val_if_fail (fd > 0, FALSE); - - if (!fu_unifying_nonblock_read (fd, - (guint8 *) msg, - sizeof(FuUnifyingHidppMsg), - &read_size, - timeout, - error)) { + if (!fu_io_channel_read_raw (io_channel, + (guint8 *) msg, + sizeof(FuUnifyingHidppMsg), + &read_size, + timeout, + FU_IO_CHANNEL_FLAG_SINGLE_SHOT, + error)) { g_prefix_error (error, "failed to receive: "); return FALSE; } @@ -133,26 +130,24 @@ fu_unifying_hidpp_receive (gint fd, } gboolean -fu_unifying_hidpp_transfer (gint fd, FuUnifyingHidppMsg *msg, GError **error) +fu_unifying_hidpp_transfer (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, GError **error) { guint timeout = FU_UNIFYING_DEVICE_TIMEOUT_MS; guint ignore_cnt = 0; g_autoptr(FuUnifyingHidppMsg) msg_tmp = fu_unifying_hidpp_msg_new (); - g_return_val_if_fail (fd > 0, FALSE); - /* increase timeout for some operations */ if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT) timeout *= 10; /* send request */ - if (!fu_unifying_hidpp_send (fd, msg, timeout, error)) + if (!fu_unifying_hidpp_send (io_channel, msg, timeout, error)) return FALSE; /* keep trying to receive until we get a valid reply */ while (1) { msg_tmp->hidpp_version = msg->hidpp_version; - if (!fu_unifying_hidpp_receive (fd, msg_tmp, timeout, error)) { + if (!fu_unifying_hidpp_receive (io_channel, msg_tmp, timeout, error)) { g_prefix_error (error, "failed to receive: "); return FALSE; } diff --git a/plugins/unifying/fu-unifying-hidpp.h b/plugins/unifying/fu-unifying-hidpp.h index 9a52d7e81..bcc05dd4f 100644 --- a/plugins/unifying/fu-unifying-hidpp.h +++ b/plugins/unifying/fu-unifying-hidpp.h @@ -9,6 +9,8 @@ #include +#include "fu-io-channel.h" + G_BEGIN_DECLS /* @@ -136,15 +138,15 @@ G_BEGIN_DECLS #include "fu-unifying-hidpp-msg.h" -gboolean fu_unifying_hidpp_send (gint fd, +gboolean fu_unifying_hidpp_send (FuIOChannel *self, FuUnifyingHidppMsg *msg, guint timeout, GError **error); -gboolean fu_unifying_hidpp_receive (gint fd, +gboolean fu_unifying_hidpp_receive (FuIOChannel *self, FuUnifyingHidppMsg *msg, guint timeout, GError **error); -gboolean fu_unifying_hidpp_transfer (gint fd, +gboolean fu_unifying_hidpp_transfer (FuIOChannel *self, FuUnifyingHidppMsg *msg, GError **error); diff --git a/plugins/unifying/fu-unifying-peripheral.c b/plugins/unifying/fu-unifying-peripheral.c index d6ef53642..b8253c615 100644 --- a/plugins/unifying/fu-unifying-peripheral.c +++ b/plugins/unifying/fu-unifying-peripheral.c @@ -7,7 +7,6 @@ #include "config.h" #include -#include #include "fu-unifying-common.h" #include "fu-unifying-peripheral.h" @@ -22,7 +21,7 @@ struct _FuUnifyingPeripheral guint8 hidpp_version; gboolean is_updatable; gboolean is_active; - gint udev_fd; + FuIOChannel *io_channel; GPtrArray *feature_index; /* of FuUnifyingHidppMap */ }; @@ -136,7 +135,7 @@ fu_unifying_peripheral_ping (FuUnifyingPeripheral *self, GError **error) msg->data[1] = 0x00; msg->data[2] = 0xaa; /* user-selected value */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, &error_local)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) { if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) { @@ -181,11 +180,9 @@ static gboolean fu_unifying_peripheral_close (FuDevice *device, GError **error) { FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); - if (self->udev_fd > 0) { - if (!g_close (self->udev_fd, error)) - return FALSE; - self->udev_fd = 0; - } + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); return TRUE; } @@ -206,7 +203,7 @@ fu_unifying_peripheral_poll (FuDevice *device, GError **error) /* flush pending data */ msg->device_id = self->hidpp_id; msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_receive (self->udev_fd, msg, timeout, &error_local)) { + if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) { if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { @@ -242,8 +239,8 @@ fu_unifying_peripheral_open (FuDevice *device, GError **error) const gchar *devpath = g_udev_device_get_device_file (udev_device); /* open */ - self->udev_fd = fu_unifying_nonblock_open (devpath, error); - if (self->udev_fd < 0) + self->io_channel = fu_io_channel_new_file (devpath, error); + if (self->io_channel == NULL) return FALSE; return TRUE; @@ -255,8 +252,6 @@ fu_unifying_peripheral_to_string (FuDevice *device, GString *str) FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); g_string_append_printf (str, " HidppVersion:\t\t%u\n", self->hidpp_version); - if (self->udev_fd > 0) - g_string_append_printf (str, " UdevDevice:\t\t%i\n", self->udev_fd); if (self->hidpp_id != HIDPP_DEVICE_ID_UNSET) g_string_append_printf (str, " HidppId:\t\t0x%02x\n", (guint) self->hidpp_id); if (self->battery_level != 0) @@ -301,7 +296,7 @@ fu_unifying_peripheral_fetch_firmware_info (FuUnifyingPeripheral *self, GError * msg->sub_id = idx; msg->function_id = 0x00 << 4; /* getCount */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get firmware count: "); return FALSE; } @@ -319,7 +314,7 @@ fu_unifying_peripheral_fetch_firmware_info (FuUnifyingPeripheral *self, GError * msg->sub_id = idx; msg->function_id = 0x01 << 4; /* getInfo */ msg->data[0] = i; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get firmware info: "); return FALSE; } @@ -371,7 +366,7 @@ fu_unifying_peripheral_fetch_battery_level (FuUnifyingPeripheral *self, GError * msg->sub_id = idx; msg->function_id = 0x00; /* GetBatteryLevelStatus */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get battery info: "); return FALSE; } @@ -389,7 +384,7 @@ fu_unifying_peripheral_fetch_battery_level (FuUnifyingPeripheral *self, GError * msg->sub_id = HIDPP_SUBID_GET_REGISTER; msg->function_id = HIDPP_REGISTER_BATTERY_MILEAGE; msg->hidpp_version = self->hidpp_version; - if (fu_unifying_hidpp_transfer (self->udev_fd, msg, NULL)) { + if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) { if (msg->data[0] != 0x00) self->battery_level = msg->data[0]; return TRUE; @@ -397,7 +392,7 @@ fu_unifying_peripheral_fetch_battery_level (FuUnifyingPeripheral *self, GError * /* try HID++1.0 battery status instead */ msg->function_id = HIDPP_REGISTER_BATTERY_STATUS; - if (fu_unifying_hidpp_transfer (self->udev_fd, msg, NULL)) { + if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) { switch (msg->data[0]) { case 1: /* 0 - 10 */ self->battery_level = 5; @@ -440,7 +435,7 @@ fu_unifying_hidpp_feature_search (FuDevice *device, guint16 feature, GError **er msg->data[1] = feature; msg->data[2] = 0x00; msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get idx for feature %s [0x%04x]: ", fu_unifying_hidpp_feature_to_string (feature), feature); @@ -551,7 +546,7 @@ fu_unifying_peripheral_setup (FuDevice *device, GError **error) msg->sub_id = idx; msg->function_id = 0x02 << 4; /* getDeviceType */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get device type: "); return FALSE; } @@ -578,7 +573,7 @@ fu_unifying_peripheral_setup (FuDevice *device, GError **error) msg->sub_id = idx; msg->function_id = 0x00 << 4; /* getDfuStatus */ msg->hidpp_version = self->hidpp_version; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to get DFU status: "); return FALSE; } @@ -631,7 +626,7 @@ fu_unifying_peripheral_detach (FuDevice *device, GError **error) msg->hidpp_version = self->hidpp_version; msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID | FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to put device into DFU mode: "); return FALSE; } @@ -654,7 +649,7 @@ fu_unifying_peripheral_detach (FuDevice *device, GError **error) msg->data[5] = 'F'; msg->data[6] = 'U'; msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to put device into DFU mode: "); return FALSE; } @@ -833,7 +828,7 @@ fu_unifying_peripheral_write_firmware_pkt (FuUnifyingPeripheral *self, msg->function_id = cmd << 4; /* dfuStart or dfuCmdDataX */ msg->hidpp_version = self->hidpp_version; memcpy (msg->data, data, 16); - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, &error_local)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) { g_prefix_error (error, "failed to supply program data: "); return FALSE; } @@ -860,7 +855,7 @@ fu_unifying_peripheral_write_firmware_pkt (FuUnifyingPeripheral *self, for (guint retry = 0; retry < 10; retry++) { g_autoptr(FuUnifyingHidppMsg) msg2 = fu_unifying_hidpp_msg_new (); msg2->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID; - if (!fu_unifying_hidpp_receive (self->udev_fd, msg2, 15000, error)) + if (!fu_unifying_hidpp_receive (self->io_channel, msg2, 15000, error)) return FALSE; if (fu_unifying_hidpp_msg_is_reply (msg, msg2)) { g_autoptr(GError) error2 = NULL; @@ -956,7 +951,7 @@ fu_unifying_peripheral_attach (FuDevice *device, GError **error) msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID | FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID | // inferred? FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to restart device: "); return FALSE; } diff --git a/plugins/unifying/fu-unifying-runtime.c b/plugins/unifying/fu-unifying-runtime.c index 622d8523b..7ba1eac4f 100644 --- a/plugins/unifying/fu-unifying-runtime.c +++ b/plugins/unifying/fu-unifying-runtime.c @@ -7,7 +7,6 @@ #include "config.h" #include -#include #include "fu-unifying-common.h" #include "fu-unifying-runtime.h" @@ -18,7 +17,7 @@ struct _FuUnifyingRuntime FuUdevDevice parent_instance; guint8 version_bl_major; gboolean signed_firmware; - gint udev_fd; + FuIOChannel *io_channel; }; G_DEFINE_TYPE (FuUnifyingRuntime, fu_unifying_runtime, FU_TYPE_UDEV_DEVICE) @@ -31,9 +30,6 @@ static void fu_unifying_runtime_to_string (FuDevice *device, GString *str) { FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); - - if (self->udev_fd > 0) - g_string_append_printf (str, " UdevDevice:\t\t%i\n", self->udev_fd); g_string_append_printf (str, " SignedFirmware:\t%i\n", self->signed_firmware); } @@ -49,18 +45,16 @@ fu_unifying_runtime_enable_notifications (FuUnifyingRuntime *self, GError **erro msg->data[1] = 0x05; /* Wireless + SoftwarePresent */ msg->data[2] = 0x00; msg->hidpp_version = 1; - return fu_unifying_hidpp_transfer (self->udev_fd, msg, error); + return fu_unifying_hidpp_transfer (self->io_channel, msg, error); } static gboolean fu_unifying_runtime_close (FuDevice *device, GError **error) { FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); - if (self->udev_fd > 0) { - if (!g_close (self->udev_fd, error)) - return FALSE; - self->udev_fd = 0; - } + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); return TRUE; } @@ -80,7 +74,7 @@ fu_unifying_runtime_poll (FuDevice *device, GError **error) /* is there any pending data to read */ msg->hidpp_version = 1; - if (!fu_unifying_hidpp_receive (self->udev_fd, msg, timeout, &error_local)) { + if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) { if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { @@ -126,8 +120,8 @@ fu_unifying_runtime_open (FuDevice *device, GError **error) const gchar *devpath = g_udev_device_get_device_file (udev_device); /* open, but don't block */ - self->udev_fd = fu_unifying_nonblock_open (devpath, error); - if (self->udev_fd < 0) + self->io_channel = fu_io_channel_new_file (devpath, error); + if (self->io_channel == NULL) return FALSE; /* poll for notifications */ @@ -208,7 +202,7 @@ fu_unifying_runtime_setup_internal (FuDevice *device, GError **error) msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION; msg->data[0] = i; msg->hidpp_version = 1; - if (!fu_unifying_hidpp_transfer (self->udev_fd, msg, error)) { + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { g_prefix_error (error, "failed to read device config: "); return FALSE; } @@ -286,7 +280,7 @@ fu_unifying_runtime_detach (FuDevice *device, GError **error) msg->data[2] = 'P'; msg->hidpp_version = 1; msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!fu_unifying_hidpp_send (self->udev_fd, msg, FU_UNIFYING_DEVICE_TIMEOUT_MS, error)) { + if (!fu_unifying_hidpp_send (self->io_channel, msg, FU_UNIFYING_DEVICE_TIMEOUT_MS, error)) { g_prefix_error (error, "failed to detach to bootloader: "); return FALSE; } diff --git a/src/fu-io-channel.c b/src/fu-io-channel.c new file mode 100644 index 000000000..ce9083b38 --- /dev/null +++ b/src/fu-io-channel.c @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuIOChannel" + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fwupd-error.h" +#include "fu-common.h" +#include "fu-io-channel.h" + +struct _FuIOChannel { + GObject parent_instance; + gint fd; +}; + +G_DEFINE_TYPE (FuIOChannel, fu_io_channel, G_TYPE_OBJECT) + +/** + * fu_io_channel_unix_get_fd: + * @self: a #FuIOChannel + * + * Gets the file descriptor for the device. + * + * Returns: fd, or -1 for not open. + * + * Since: 1.2.2 + **/ +gint +fu_io_channel_unix_get_fd (FuIOChannel *self) +{ + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), -1); + return self->fd; +} + +/** + * fu_io_channel_shutdown: + * @self: a #FuIOChannel + * @error: a #GError, or %NULL + * + * Closes the file descriptor for the device. + * + * Returns: %TRUE if all the FD was closed. + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_shutdown (FuIOChannel *self, GError **error) +{ + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + if (!g_close (self->fd, error)) + return FALSE; + self->fd = -1; + return TRUE; +} + +static gboolean +fu_io_channel_flush_input (FuIOChannel *self, GError **error) +{ + GPollFD poll = { + .fd = self->fd, + .events = G_IO_IN | G_IO_ERR, + }; + while (g_poll (&poll, 1, 0) > 0) { + gchar c; + gint r = read (self->fd, &c, 1); + if (r < 0 && errno != EINTR) + break; + } + return TRUE; +} + +/** + * fu_io_channel_write_bytes: + * @self: a #FuIOChannel + * @bytes: buffer to write + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Writes bytes to the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: %TRUE if all the bytes was written + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_write_bytes (FuIOChannel *self, + GBytes *bytes, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (bytes, &bufsz); + return fu_io_channel_write_raw (self, buf, bufsz, timeout_ms, flags, error); +} + +/** + * fu_io_channel_write_raw: + * @self: a #FuIOChannel + * @data: buffer to write + * @datasz: size of @data + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Writes bytes to the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: %TRUE if all the bytes was written + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_write_raw (FuIOChannel *self, + const guint8 *data, + gsize datasz, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + gsize idx = 0; + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + + /* flush pending reads */ + if (flags & FU_IO_CHANNEL_FLAG_FLUSH_INPUT) { + if (!fu_io_channel_flush_input (self, error)) + return FALSE; + } + + /* blocking IO */ + if (flags & FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO) { + gssize wrote = write (self->fd, data, datasz); + if (wrote != (gssize) datasz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write: " + "wrote %" G_GSSIZE_FORMAT " of %" G_GSIZE_FORMAT, + wrote, datasz); + return FALSE; + } + return TRUE; + } + + /* nonblocking IO */ + while (idx < datasz) { + gint rc; + GPollFD fds = { + .fd = self->fd, + .events = G_IO_OUT | G_IO_ERR, + }; + + /* wait for data to be allowed to write without blocking */ + rc = g_poll (&fds, 1, (gint) timeout_ms); + if (rc == 0) + break; + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to poll %i", + self->fd); + return FALSE; + } + + /* we can write data */ + if (fds.revents & G_IO_OUT) { + gssize len = write (self->fd, data + idx, datasz - idx); + if (len < 0) { + if (errno == EAGAIN) { + g_debug ("got EAGAIN, trying harder"); + continue; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to write %" G_GSIZE_FORMAT + " bytes to %i: %s" , + datasz, + self->fd, + strerror (errno)); + return FALSE; + } + if (flags & FU_IO_CHANNEL_FLAG_SINGLE_SHOT) + break; + idx += len; + } + } + + return TRUE; +} + +/** + * fu_io_channel_read_bytes: + * @self: a #FuIOChannel + * @max_size: maximum size of the returned blob, or -1 for no limit + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Reads bytes from the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: a #GBytes, or %NULL for error + * + * Since: 1.2.2 + **/ +GBytes * +fu_io_channel_read_bytes (FuIOChannel *self, + gssize max_size, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + GPollFD fds = { + .fd = self->fd, + .events = G_IO_IN | G_IO_PRI | G_IO_ERR, + }; + g_autoptr(GString) str = g_string_new (NULL); + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), NULL); + + /* blocking IO */ + if (flags & FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO) { + guint8 buf[1024]; + gssize len = read (self->fd, buf, sizeof (buf)); + if (len < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read %i: %s", self->fd, + strerror (errno)); + return NULL; + } + if (len > 0) + g_string_append_len (str, (gchar *) buf, len); + return g_bytes_new (str->str, str->len); + } + + /* nonblocking IO */ + while (TRUE) { + /* wait for data to appear */ + gint rc = g_poll (&fds, 1, (gint) timeout_ms); + if (rc == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timeout"); + return FALSE; + } + if (rc < 0) { + if (errno == EINTR) + continue; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to poll %i", self->fd); + return NULL; + } + + /* we have data to read */ + if (fds.revents & G_IO_IN) { + guint8 buf[1024]; + gssize len = read (self->fd, buf, sizeof (buf)); + if (len < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + continue; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read %i: %s", self->fd, + strerror (errno)); + return NULL; + } + if (len > 0) + g_string_append_len (str, (gchar *) buf, len); + + /* check maximum size */ + if (max_size > 0 && str->len >= (guint) max_size) + break; + if (flags & FU_IO_CHANNEL_FLAG_SINGLE_SHOT) + break; + continue; + } + if (fds.revents & G_IO_ERR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "error condition"); + return NULL; + } + if (fds.revents & G_IO_HUP) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "connection hung up"); + return NULL; + } + if (fds.revents & G_IO_NVAL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid request"); + return NULL; + } + } + + /* no data */ + if (str->len == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "no data received from device in %ums", + timeout_ms); + return NULL; + } + + /* return blob */ + return g_bytes_new (str->str, str->len); +} + +/** + * fu_io_channel_read_raw: + * @self: a #FuIOChannel + * @buf: buffer, or %NULL + * @bufsz: size of @buf + * @bytes_read: (out): data written to @buf, or %NULL + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Reads bytes from the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: a #GBytes, or %NULL for error + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_read_raw (FuIOChannel *self, + guint8 *buf, + gsize bufsz, + gsize *bytes_read, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + const guint8 *tmpbuf = NULL; + gsize bytes_read_tmp; + g_autoptr(GBytes) tmp = NULL; + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + + tmp = fu_io_channel_read_bytes (self, bufsz, timeout_ms, flags, error); + if (tmp == NULL) + return FALSE; + tmpbuf = g_bytes_get_data (tmp, &bytes_read_tmp); + if (tmpbuf != NULL) + memcpy (buf, tmpbuf, bytes_read_tmp); + if (bytes_read != NULL) + *bytes_read = bytes_read_tmp; + return TRUE; +} + +static void +fu_io_channel_finalize (GObject *object) +{ + FuIOChannel *self = FU_IO_CHANNEL (object); + if (self->fd != -1) + g_close (self->fd, NULL); + G_OBJECT_CLASS (fu_io_channel_parent_class)->finalize (object); +} + +static void +fu_io_channel_class_init (FuIOChannelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_io_channel_finalize; +} + +static void +fu_io_channel_init (FuIOChannel *self) +{ + self->fd = -1; +} + +/** + * fu_io_channel_unix_new: + * @fd: file descriptor + * + * Creates a new object to write and read from. + * + * Returns: a #FuIOChannel + **/ +FuIOChannel * +fu_io_channel_unix_new (gint fd) +{ + FuIOChannel *self; + self = g_object_new (FU_TYPE_IO_CHANNEL, NULL); + self->fd = fd; + return FU_IO_CHANNEL (self); +} + +/** + * fu_io_channel_new_file: + * @filename: device file + * @error: a #GError, or %NULL + * + * Creates a new object to write and read from. + * + * Returns: a #FuIOChannel + **/ +FuIOChannel * +fu_io_channel_new_file (const gchar *filename, GError **error) +{ + gint fd = g_open (filename, O_RDWR | O_NONBLOCK, S_IRWXU); + if (fd < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to open %s", filename); + return NULL; + } + return fu_io_channel_unix_new (fd); +} diff --git a/src/fu-io-channel.h b/src/fu-io-channel.h new file mode 100644 index 000000000..c8a7d0daa --- /dev/null +++ b/src/fu-io-channel.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_IO_CHANNEL_H +#define __FU_IO_CHANNEL_H + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_IO_CHANNEL (fu_io_channel_get_type ()) + +G_DECLARE_FINAL_TYPE (FuIOChannel, fu_io_channel, FU, IO_CHANNEL, GObject) + +/** + * FuIOChannelFlags: + * @FU_IO_CHANNEL_FLAG_NONE: No flags are set + * @FU_IO_CHANNEL_FLAG_SINGLE_SHOT: Only one read or write is expected + * @FU_IO_CHANNEL_FLAG_FLUSH_INPUT: Flush pending input before writing + * @FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO: Block waiting for the TTY + * + * The flags used when reading data from the TTY. + **/ +typedef enum { + FU_IO_CHANNEL_FLAG_NONE = 0, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_SINGLE_SHOT = 1 << 0, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_FLUSH_INPUT = 1 << 1, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO = 1 << 2, /* Since: 1.2.2 */ + /*< private >*/ + FU_IO_CHANNEL_FLAG_LAST +} FuIOChannelFlags; + +FuIOChannel *fu_io_channel_unix_new (gint fd); +FuIOChannel *fu_io_channel_new_file (const gchar *filename, + GError **error); + +gint fu_io_channel_unix_get_fd (FuIOChannel *self); +gboolean fu_io_channel_shutdown (FuIOChannel *self, + GError **error); +gboolean fu_io_channel_write_raw (FuIOChannel *self, + const guint8 *data, + gsize datasz, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +gboolean fu_io_channel_read_raw (FuIOChannel *self, + guint8 *buf, + gsize bufsz, + gsize *bytes_read, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +gboolean fu_io_channel_write_bytes (FuIOChannel *self, + GBytes *bytes, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +GBytes *fu_io_channel_read_bytes (FuIOChannel *self, + gssize max_size, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); + +G_END_DECLS + +#endif /* __FU_IO_CHANNEL_H */ diff --git a/src/meson.build b/src/meson.build index 6f7312544..427801ee1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -34,6 +34,7 @@ libfwupdprivate = static_library( 'fu-device-locker.c', 'fu-hwids.c', 'fu-history.c', + 'fu-io-channel.c', 'fu-mutex.c', 'fu-plugin.c', 'fu-progressbar.c', @@ -126,6 +127,7 @@ fwupdtool = executable( 'fu-device-locker.c', 'fu-idle.c', 'fu-install-task.c', + 'fu-io-channel.c', 'fu-keyring.c', 'fu-keyring-utils.c', 'fu-history.c', @@ -207,6 +209,7 @@ executable( 'fu-device-list.c', 'fu-device-locker.c', 'fu-idle.c', + 'fu-io-channel.c', 'fu-install-task.c', 'fu-keyring.c', 'fu-keyring-utils.c', @@ -279,6 +282,7 @@ if get_option('tests') 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', + 'fu-io-channel.c', 'fu-keyring.c', 'fu-keyring-result.c', 'fu-mutex.c', @@ -342,6 +346,7 @@ if get_option('introspection') 'fu-device.h', 'fu-device-locker.c', 'fu-device-locker.h', + 'fu-io-channel.c', 'fu-plugin.c', 'fu-plugin.h', 'fu-quirks.c', From 4badf7e963ebbe588cdf6411637533a280308417 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 7 Dec 2018 09:10:46 +0000 Subject: [PATCH 125/254] Do not allow a GUID of zero The tempation for OEMs or ODMs to ship firmware updates matching a NULL GUID is too fragile to allow -- even with CHID restrictions. --- src/fu-common-guid.c | 2 ++ src/fu-self-test.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/fu-common-guid.c b/src/fu-common-guid.c index 6adfeea96..8ec036eb1 100644 --- a/src/fu-common-guid.c +++ b/src/fu-common-guid.c @@ -97,6 +97,8 @@ fu_common_guid_is_valid (const gchar *guid) if (guid == NULL) return FALSE; rc = uuid_parse (guid, uu); + if (uuid_is_null (uu)) + return FALSE; return rc == 0; } diff --git a/src/fu-self-test.c b/src/fu-self-test.c index fc3e828a2..d57ef8949 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -299,7 +299,7 @@ fu_engine_requirements_other_device_func (void) const gchar *xml = "" " " - " 00000000-0000-0000-0000-000000000000" + " 1ff60ab2-3905-06a1-b476-0371f00c9e9b" " " " " " 12345678-1234-1234-1234-123456789012" @@ -324,7 +324,7 @@ fu_engine_requirements_other_device_func (void) fu_device_set_name (device2, "Secondary firmware"); fu_device_set_version (device2, "4.5.6"); fu_device_set_vendor_id (device2, "FFFF"); - fu_device_add_guid (device2, "00000000-0000-0000-0000-000000000000"); + fu_device_add_guid (device2, "1ff60ab2-3905-06a1-b476-0371f00c9e9b"); fu_engine_add_device (engine, device2); /* import firmware metainfo */ @@ -3092,6 +3092,7 @@ fu_common_guid_func (void) g_assert (!fu_common_guid_is_valid ("1ff60ab2-3905-06a1-b476")); g_assert (!fu_common_guid_is_valid ("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9b")); g_assert (!fu_common_guid_is_valid (" 1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + g_assert (!fu_common_guid_is_valid ("00000000-0000-0000-0000-000000000000")); /* valid */ g_assert (fu_common_guid_is_valid ("1ff60ab2-3905-06a1-b476-0371f00c9e9b")); From a0da340b608f8fcdce9cd8fca4e777151e8ab47e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 7 Dec 2018 09:12:42 +0000 Subject: [PATCH 126/254] uefi: Do not add devices with invalid GUIDs Note: We deliberately don't add the device without 'UPDATABLE' as there's nothing the user can actually do to repair this themselves. --- plugins/uefi/fu-plugin-uefi.c | 7 ++++++- plugins/uefi/fu-self-test.c | 14 +++++++++++--- plugins/uefi/fu-uefi-device.c | 15 ++++++++++++--- plugins/uefi/fu-uefi-device.h | 3 ++- plugins/uefi/fu-uefi-tool.c | 8 +++++++- .../tests/efi/esrt/entries/entry2/capsule_flags | 1 + .../uefi/tests/efi/esrt/entries/entry2/fw_class | 1 + .../uefi/tests/efi/esrt/entries/entry2/fw_type | 1 + .../uefi/tests/efi/esrt/entries/entry2/fw_version | 1 + .../efi/esrt/entries/entry2/last_attempt_status | 1 + .../efi/esrt/entries/entry2/last_attempt_version | 1 + .../entries/entry2/lowest_supported_fw_version | 1 + 12 files changed, 45 insertions(+), 9 deletions(-) create mode 120000 plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags create mode 100644 plugins/uefi/tests/efi/esrt/entries/entry2/fw_class create mode 120000 plugins/uefi/tests/efi/esrt/entries/entry2/fw_type create mode 120000 plugins/uefi/tests/efi/esrt/entries/entry2/fw_version create mode 120000 plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status create mode 120000 plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version create mode 120000 plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index c9ec9cf6e..8bf396f66 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -726,7 +726,12 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) /* add each device */ for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to add %s: %s", path, error_parse->message); + continue; + } fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) return FALSE; diff --git a/plugins/uefi/fu-self-test.c b/plugins/uefi/fu-self-test.c index 6f6a0d8f5..bd9c72bb3 100644 --- a/plugins/uefi/fu-self-test.c +++ b/plugins/uefi/fu-self-test.c @@ -85,11 +85,13 @@ fu_uefi_device_func (void) { g_autofree gchar *fn = NULL; g_autoptr(FuUefiDevice) dev = NULL; + g_autoptr(GError) error = NULL; fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0"); g_assert (fn != NULL); - dev = fu_uefi_device_new_from_entry (fn); + dev = fu_uefi_device_new_from_entry (fn, &error); g_assert_nonnull (dev); + g_assert_no_error (error); g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); @@ -184,7 +186,12 @@ fu_uefi_plugin_func (void) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(FuUefiDevice) dev_tmp = fu_uefi_device_new_from_entry (path); + g_autoptr(GError) error_local = NULL; + g_autoptr(FuUefiDevice) dev_tmp = fu_uefi_device_new_from_entry (path, &error_local); + if (dev_tmp == NULL) { + g_debug ("failed to add %s: %s", path, error_local->message); + continue; + } g_ptr_array_add (devices, g_object_ref (dev_tmp)); } g_assert_cmpint (devices->len, ==, 2); @@ -220,7 +227,8 @@ fu_uefi_update_info_func (void) fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0"); g_assert (fn != NULL); - dev = fu_uefi_device_new_from_entry (fn); + dev = fu_uefi_device_new_from_entry (fn, &error); + g_assert_no_error (error); g_assert_nonnull (dev); g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 8073c2df9..2e6c22805 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -449,9 +449,9 @@ fu_uefi_device_class_init (FuUefiDeviceClass *klass) } FuUefiDevice * -fu_uefi_device_new_from_entry (const gchar *entry_path) +fu_uefi_device_new_from_entry (const gchar *entry_path, GError **error) { - FuUefiDevice *self; + g_autoptr(FuUefiDevice) self = NULL; g_autofree gchar *fw_class_fn = NULL; g_autofree gchar *id = NULL; @@ -481,7 +481,16 @@ fu_uefi_device_new_from_entry (const gchar *entry_path) self->fw_class, self->fmp_hardware_instance); fu_device_set_id (FU_DEVICE (self), id); - return self; + /* this is invalid */ + if (!fu_common_guid_is_valid (self->fw_class)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ESRT GUID '%s' was not valid", self->fw_class); + return NULL; + } + + return g_steal_pointer (&self); } FuUefiDevice * diff --git a/plugins/uefi/fu-uefi-device.h b/plugins/uefi/fu-uefi-device.h index 0bb2d6cfc..f2df02a90 100644 --- a/plugins/uefi/fu-uefi-device.h +++ b/plugins/uefi/fu-uefi-device.h @@ -40,7 +40,8 @@ typedef enum { } FuUefiDeviceStatus; FuUefiDevice *fu_uefi_device_new_from_guid (const gchar *guid); -FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path); +FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path, + GError **error); FuUefiDevice *fu_uefi_device_new_from_dev (FuDevice *dev); gboolean fu_uefi_device_clear_status (FuUefiDevice *self, GError **error); diff --git a/plugins/uefi/fu-uefi-tool.c b/plugins/uefi/fu-uefi-tool.c index 74a37c123..94ab5f2e5 100644 --- a/plugins/uefi/fu-uefi-tool.c +++ b/plugins/uefi/fu-uefi-tool.c @@ -216,7 +216,13 @@ main (int argc, char *argv[]) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < entries->len; i++) { const gchar *path = g_ptr_array_index (entries, i); - g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to parse %s: %s", + path, error_parse->message); + continue; + } fu_device_set_metadata (FU_DEVICE (dev), "EspPath", esp_path); g_ptr_array_add (devices, g_object_ref (dev)); } diff --git a/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags b/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags new file mode 120000 index 000000000..24b0ea1b5 --- /dev/null +++ b/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags @@ -0,0 +1 @@ +../entry1/capsule_flags \ No newline at end of file diff --git a/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class b/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class new file mode 100644 index 000000000..44964b11f --- /dev/null +++ b/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class @@ -0,0 +1 @@ +00000000-0000-0000-0000-000000000000 diff --git a/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type b/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type new file mode 120000 index 000000000..d7a6438a2 --- /dev/null +++ b/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type @@ -0,0 +1 @@ +../entry1/fw_type \ No newline at end of file diff --git a/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version b/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version new file mode 120000 index 000000000..3d6ce82dc --- /dev/null +++ b/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version @@ -0,0 +1 @@ +../entry1/fw_version \ No newline at end of file diff --git a/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status b/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status new file mode 120000 index 000000000..d8d4cb389 --- /dev/null +++ b/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status @@ -0,0 +1 @@ +../entry1/last_attempt_status \ No newline at end of file diff --git a/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version b/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version new file mode 120000 index 000000000..639dcb185 --- /dev/null +++ b/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version @@ -0,0 +1 @@ +../entry1/last_attempt_version \ No newline at end of file diff --git a/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version b/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version new file mode 120000 index 000000000..9b389118c --- /dev/null +++ b/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version @@ -0,0 +1 @@ +../entry1/lowest_supported_fw_version \ No newline at end of file From 8dc599a23e856ecac5675a36837dd894e565de13 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 7 Dec 2018 16:30:55 +0000 Subject: [PATCH 127/254] flashrom: Ensure the quirks database is set on the new object --- plugins/flashrom/fu-plugin-flashrom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/flashrom/fu-plugin-flashrom.c b/plugins/flashrom/fu-plugin-flashrom.c index 34ddfe2b6..ba2043be3 100644 --- a/plugins/flashrom/fu-plugin-flashrom.c +++ b/plugins/flashrom/fu-plugin-flashrom.c @@ -66,6 +66,7 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) g_autofree gchar *device_id = g_strdup_printf ("flashrom-%s", quirk_str); g_autoptr(FuDevice) dev = fu_device_new (); fu_device_set_id (dev, device_id); + fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); if (data->flashrom_fn != NULL) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); From c9d775c321decf5d4c627443863bbabbacdc5099 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 7 Dec 2018 12:11:54 -0600 Subject: [PATCH 128/254] trivial: dell-dock: Correct variable for turning off HDCP 2.2 --- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index af332b048..0fc07cfb4 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -645,7 +645,7 @@ fu_dell_dock_mst_stop_esm (FuDevice *symbiote, GError **error) if (!fu_dell_dock_mst_rc_command (symbiote, MST_CMD_WRITE_MEMORY, length, MST_REG_HDCP22_DISABLE, - data, + data_out, error)) return FALSE; From 6131f5df8f34ddb7f2d58f01cf95ff8c6f6430de Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Dec 2018 16:42:00 -0600 Subject: [PATCH 129/254] trivial: uefi: correct a logic error in setting variable efi_guid_cmp uses memcmp and hence should return 0 when a match is found. --- plugins/uefi/fu-uefi-bootmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index c70f972cb..7bec31178 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -108,7 +108,7 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si efidp found_dp; g_autofree guint8 *var_data_tmp = NULL; - if (efi_guid_cmp (guid, &efi_guid_global)) + if (efi_guid_cmp (guid, &efi_guid_global) == 0) continue; rc = sscanf (name, "Boot%hX%n", &entry, &scanned); if (rc < 0) { From 2ac3aca2a70a2ab2714cbeeac576d444be442209 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 10 Dec 2018 14:58:22 -0600 Subject: [PATCH 130/254] uefi: Append the header on capsules without headers from Linux This allows using better heuristics and potentially phasing this out in the future. --- plugins/dell/fu-self-test.c | 5 ++- plugins/uefi/efi/fwupdate.c | 70 ++++------------------------------- plugins/uefi/fu-plugin-uefi.c | 4 ++ plugins/uefi/fu-uefi-device.c | 64 +++++++++++++++++++++++++++++++- plugins/uefi/fu-uefi-device.h | 1 + 5 files changed, 80 insertions(+), 64 deletions(-) diff --git a/plugins/dell/fu-self-test.c b/plugins/dell/fu-self-test.c index ff07c4bcd..083b0b683 100644 --- a/plugins/dell/fu-self-test.c +++ b/plugins/dell/fu-self-test.c @@ -69,7 +69,7 @@ fu_plugin_dell_tpm_func (void) struct tpm_status tpm_out; g_autoptr(FuPlugin) plugin_dell = NULL; g_autoptr(FuPlugin) plugin_uefi = NULL; - g_autoptr(GBytes) blob_fw = g_bytes_new_static ("fw", 2); + g_autoptr(GBytes) blob_fw = g_bytes_new_static ("fw", 30); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; @@ -244,8 +244,11 @@ fu_plugin_dell_tpm_func (void) g_clear_error (&error); /* test override */ + g_test_expect_message ("FuPluginUefi", G_LOG_LEVEL_WARNING, + "missing or invalid embedded capsule header"); ret = fu_plugin_runner_update (plugin_uefi, device_v20, NULL, blob_fw, FWUPD_INSTALL_FLAG_FORCE, &error); + g_test_assert_expected_messages (); g_assert_no_error (error); g_assert (ret); } diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index 3cbe16f6d..ecf621946 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -19,8 +19,6 @@ EFI_GUID fwupdate_guid = {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; EFI_GUID ux_capsule_guid = {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; -EFI_GUID fmp_capsule_guid = - {0x6dcbd5ed,0xe82d,0x4c44,{0xbd,0xa1,0x71,0x94,0x19,0x9a,0xd9,0x2a}}; EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; @@ -1017,7 +1015,6 @@ do_ux_csum(EFI_HANDLE loaded_image, UINT8 *buf, UINTN size) } #define is_ux_capsule(guid) (guid_cmp(guid, &ux_capsule_guid) == 0) -#define is_fmp_capsule(guid) (guid_cmp(guid, &fmp_capsule_guid) == 0) static EFI_STATUS add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out, @@ -1047,68 +1044,17 @@ add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out, dprint(L"updates guid: %g\n", &update->info->guid); dprint(L"File guid: %g\n", fbuf); - /* - * See if it has the capsule header, and if not, add one. - * - * Unfortunately there's not a good way to do this, so we're just - * checking if the capsule has the fw_class guid at the right place. - */ - if ((guid_cmp(&update->info->guid, (efi_guid_t *)fbuf) == 0 || - is_fmp_capsule((efi_guid_t *)fbuf)) && - /* - * We're ignoring things that are 40 bytes here, because that's - * the size of the variables used in the test code I wrote for - * edk2 - It's basically a capsule header with no payload, so - * there's nothing real it can do anyway. - * - * At some point I'll update that to be slightly different and - * take the exception out, but it's not pressing. - */ - fsize != 40) { - dprint(L"Image has capsule image embedded\n"); - cbd_len = fsize; - cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; - capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; - if (!cap_out->Flags && !is_ux_capsule(&update->info->guid)) { + cbd_len = fsize; + cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; + capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; + if (!cap_out->Flags && !is_ux_capsule(&update->info->guid)) { #if defined(__aarch64__) - cap_out->Flags |= update->info->capsule_flags; + cap_out->Flags |= update->info->capsule_flags; #else - cap_out->Flags |= update->info->capsule_flags | - CAPSULE_FLAGS_PERSIST_ACROSS_RESET | - CAPSULE_FLAGS_INITIATE_RESET; + cap_out->Flags |= update->info->capsule_flags | + CAPSULE_FLAGS_PERSIST_ACROSS_RESET | + CAPSULE_FLAGS_INITIATE_RESET; #endif - } - } else { - dprint(L"Image does not have embedded header\n"); - dprint(L"Allocating %d for capsule header.\n", - sizeof (*capsule)+fsize); - rc = allocate((void **)&capsule, sizeof (*capsule) + fsize); - if (EFI_ERROR(rc)) { - print(L"Tried to allocate %d\n", - sizeof (*capsule) + fsize); - print(L"Could not allocate space for update: %r.\n", - rc); - return EFI_OUT_OF_RESOURCES; - } - capsule->CapsuleGuid = update->info->guid; - capsule->HeaderSize = sizeof (*capsule); - if (!is_ux_capsule(&update->info->guid)) { -#if defined(__aarch64__) - capsule->Flags |= update->info->capsule_flags; -#else - capsule->Flags = update->info->capsule_flags | - CAPSULE_FLAGS_PERSIST_ACROSS_RESET | - CAPSULE_FLAGS_INITIATE_RESET; -#endif - } - capsule->CapsuleImageSize = fsize + sizeof (*capsule); - - UINT8 *buffer = (UINT8 *)capsule + capsule->HeaderSize; - CopyMem(buffer, fbuf, fsize); - cbd_len = capsule->CapsuleImageSize; - cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)capsule; - cap_out = capsule; - free(fbuf, fsize); } if (is_ux_capsule(&update->info->guid)) { diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 8bf396f66..8d2d3728f 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -377,6 +377,10 @@ fu_plugin_update (FuPlugin *plugin, if (!fu_device_write_firmware (device, blob_fw, error)) return FALSE; + /* record if we had an invalid header during update */ + str = fu_uefi_missing_capsule_header (device) ? "True" : "False"; + fu_plugin_add_report_metadata (plugin, "MissingCapsuleHeader", str); + /* record boot information to system log for future debugging */ efibootmgr_path = fu_common_find_program_in_path ("efibootmgr", NULL); if (efibootmgr_path != NULL) { diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 2e6c22805..aff961a38 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -28,6 +28,7 @@ struct _FuUefiDevice { FuUefiDeviceStatus last_attempt_status; guint32 last_attempt_version; guint64 fmp_hardware_instance; + gboolean missing_header; }; G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE) @@ -289,6 +290,63 @@ fu_uefi_device_build_dp_buf (const gchar *path, gsize *bufsz, GError **error) return g_steal_pointer (&dp_buf); } +static GBytes * +fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + gsize fw_length; + efi_guid_t esrt_guid; + efi_guid_t payload_guid; + const gchar *data = g_bytes_get_data (fw, &fw_length); + self->missing_header = FALSE; + + /* convert to EFI GUIDs */ + if (efi_str_to_guid (fu_uefi_device_get_guid (self), &esrt_guid) < 0) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Invalid ESRT GUID"); + return NULL; + } + if (fw_length < sizeof(efi_guid_t)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Invalid payload"); + return NULL; + } + memcpy (&payload_guid, data, sizeof(efi_guid_t)); + + /* ESRT header matches payload */ + if (efi_guid_cmp (&esrt_guid, &payload_guid) == 0) { + g_debug ("ESRT matches payload GUID"); + return g_bytes_new_from_bytes (fw, 0, fw_length); + /* FMP payload */ + } else if (fu_uefi_device_get_kind (self) == FU_UEFI_DEVICE_KIND_FMP) { + g_debug ("performing FMP update"); + return g_bytes_new_from_bytes (fw, 0, fw_length); + /* Missing, add a header */ + } else { + guint header_size = sizeof(efi_capsule_header_t); + guint8 *new_data = g_malloc (fw_length + header_size); + guint8 *capsule = new_data + header_size; + efi_capsule_header_t *header = (efi_capsule_header_t *) new_data; + + g_warning ("missing or invalid embedded capsule header"); + self->missing_header = TRUE; + header->flags = self->capsule_flags; + header->header_size = header_size; + header->capsule_image_size = fw_length + header_size; + memcpy (&header->guid, &esrt_guid, sizeof (efi_guid_t)); + memcpy (capsule, data, fw_length); + + return g_bytes_new_take (new_data, fw_length + header_size); + } +} + +gboolean +fu_uefi_missing_capsule_header (FuDevice *device) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + return self->missing_header; +} + static gboolean fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) { @@ -299,6 +357,7 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) efi_update_info_t info; gsize datasz = 0; gsize dp_bufsz = 0; + g_autoptr(GBytes) fixed_fw = NULL; g_autofree gchar *basename = NULL; g_autofree gchar *directory = NULL; g_autofree gchar *fn = NULL; @@ -320,7 +379,10 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) fn = g_build_filename (directory, "fw", basename, NULL); if (!fu_common_mkdir_parent (fn, error)) return FALSE; - if (!fu_common_set_contents_bytes (fn, fw, error)) + fixed_fw = fu_uefi_device_fixup_firmware (device, fw, error); + if (fixed_fw == NULL) + return FALSE; + if (!fu_common_set_contents_bytes (fn, fixed_fw, error)) return FALSE; /* set the blob header shared with fwupd.efi */ diff --git a/plugins/uefi/fu-uefi-device.h b/plugins/uefi/fu-uefi-device.h index f2df02a90..98aee51b4 100644 --- a/plugins/uefi/fu-uefi-device.h +++ b/plugins/uefi/fu-uefi-device.h @@ -57,6 +57,7 @@ const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind); const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status); FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error); +gboolean fu_uefi_missing_capsule_header (FuDevice *device); G_END_DECLS From 8612318158c9d199d539dd4d0dfcc33d4264d8fa Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 11 Dec 2018 12:33:23 -0600 Subject: [PATCH 131/254] uefi: When adding headers set the header size to 4k This solves issues with implementations that require 4k alignment of pages in BIOS which is seen on certain architectures. The UEFI spec prescribes that the "minimum" size is the size of the EFI header but that this may be increased up to larger sizes due to extended header entries. --- plugins/uefi/fu-uefi-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index aff961a38..89ee340b1 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -323,7 +323,7 @@ fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) return g_bytes_new_from_bytes (fw, 0, fw_length); /* Missing, add a header */ } else { - guint header_size = sizeof(efi_capsule_header_t); + guint header_size = getpagesize(); guint8 *new_data = g_malloc (fw_length + header_size); guint8 *capsule = new_data + header_size; efi_capsule_header_t *header = (efi_capsule_header_t *) new_data; From 9729584ee481b3bc010d5d632b64d7071bb434ec Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 13 Dec 2018 10:14:05 +0000 Subject: [PATCH 132/254] Allow plugins to define support for a 'well-known' protocol Future metadata from the LVFS will set the protocol the firmware is expected to use. As vendors love to re-use common terms like DFU for incompatible protocols, namespace them with the controlling company ID with an approximate reverse DNS namespace. This also allows more than one plugin to define support for the same protocol, for instance rts54hid+rts54hub and synapticsmst+dell-dock. --- plugins/altos/fu-plugin-altos.c | 1 + plugins/colorhug/fu-plugin-colorhug.c | 1 + plugins/csr/fu-plugin-csr.c | 1 + plugins/dell-dock/fu-plugin-dell-dock.c | 2 ++ plugins/dfu/fu-plugin-dfu.c | 2 ++ plugins/ebitdo/fu-plugin-ebitdo.c | 1 + plugins/fastboot/fu-plugin-fastboot.c | 1 + plugins/flashrom/fu-plugin-flashrom.c | 1 + plugins/nvme/fu-plugin-nvme.c | 1 + plugins/redfish/fu-plugin-redfish.c | 1 + plugins/rts54hid/fu-plugin-rts54hid.c | 1 + plugins/rts54hub/fu-plugin-rts54hub.c | 1 + plugins/synapticsmst/fu-plugin-synapticsmst.c | 1 + plugins/test/fu-plugin-test.c | 1 + plugins/thunderbolt/fu-plugin-thunderbolt.c | 1 + plugins/uefi/fu-plugin-uefi.c | 1 + plugins/unifying/fu-plugin-unifying.c | 2 ++ plugins/wacom-usb/fu-plugin-wacom-usb.c | 1 + src/fu-plugin.h | 2 ++ 19 files changed, 23 insertions(+) diff --git a/plugins/altos/fu-plugin-altos.c b/plugins/altos/fu-plugin-altos.c index a7b7520a3..8cfdc3bd6 100644 --- a/plugins/altos/fu-plugin-altos.c +++ b/plugins/altos/fu-plugin-altos.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.altusmetrum.altos"); } gboolean diff --git a/plugins/colorhug/fu-plugin-colorhug.c b/plugins/colorhug/fu-plugin-colorhug.c index 918617ad7..1fc356627 100644 --- a/plugins/colorhug/fu-plugin-colorhug.c +++ b/plugins/colorhug/fu-plugin-colorhug.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.hughski.colorhug"); } gboolean diff --git a/plugins/csr/fu-plugin-csr.c b/plugins/csr/fu-plugin-csr.c index 3ccc92778..aaedbbca2 100644 --- a/plugins/csr/fu-plugin-csr.c +++ b/plugins/csr/fu-plugin-csr.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.qualcomm.dfu"); } gboolean diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index a8845e1a7..eca46ed57 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -30,6 +30,8 @@ void fu_plugin_init (FuPlugin *plugin) /* currently slower performance, but more reliable in corner cases */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "synapticsmst"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.dell.dock"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst"); } static gboolean diff --git a/plugins/dfu/fu-plugin-dfu.c b/plugins/dfu/fu-plugin-dfu.c index 4ebd7a651..18060a7c4 100644 --- a/plugins/dfu/fu-plugin-dfu.c +++ b/plugins/dfu/fu-plugin-dfu.c @@ -14,6 +14,8 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.usb.dfu"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.st.dfuse"); } static void diff --git a/plugins/ebitdo/fu-plugin-ebitdo.c b/plugins/ebitdo/fu-plugin-ebitdo.c index fc5a63646..60a6581e0 100644 --- a/plugins/ebitdo/fu-plugin-ebitdo.c +++ b/plugins/ebitdo/fu-plugin-ebitdo.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.8bitdo"); } gboolean diff --git a/plugins/fastboot/fu-plugin-fastboot.c b/plugins/fastboot/fu-plugin-fastboot.c index 694d1cddc..b2ad4023f 100644 --- a/plugins/fastboot/fu-plugin-fastboot.c +++ b/plugins/fastboot/fu-plugin-fastboot.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.google.fastboot"); } gboolean diff --git a/plugins/flashrom/fu-plugin-flashrom.c b/plugins/flashrom/fu-plugin-flashrom.c index ba2043be3..11866d059 100644 --- a/plugins/flashrom/fu-plugin-flashrom.c +++ b/plugins/flashrom/fu-plugin-flashrom.c @@ -33,6 +33,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.flashrom"); } void diff --git a/plugins/nvme/fu-plugin-nvme.c b/plugins/nvme/fu-plugin-nvme.c index 21703b9ca..b1f89d7ce 100644 --- a/plugins/nvme/fu-plugin-nvme.c +++ b/plugins/nvme/fu-plugin-nvme.c @@ -32,6 +32,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_udev_subsystem (plugin, "nvme"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.nvmexpress"); } gboolean diff --git a/plugins/redfish/fu-plugin-redfish.c b/plugins/redfish/fu-plugin-redfish.c index 1cd90c397..918801acd 100644 --- a/plugins/redfish/fu-plugin-redfish.c +++ b/plugins/redfish/fu-plugin-redfish.c @@ -117,6 +117,7 @@ fu_plugin_init (FuPlugin *plugin) { FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); data->client = fu_redfish_client_new (); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.dmtf.redfish"); } void diff --git a/plugins/rts54hid/fu-plugin-rts54hid.c b/plugins/rts54hid/fu-plugin-rts54hid.c index a8ebc5d03..00621399d 100644 --- a/plugins/rts54hid/fu-plugin-rts54hid.c +++ b/plugins/rts54hid/fu-plugin-rts54hid.c @@ -15,6 +15,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); /* register the custom types */ g_type_ensure (FU_TYPE_RTS54HID_MODULE); diff --git a/plugins/rts54hub/fu-plugin-rts54hub.c b/plugins/rts54hub/fu-plugin-rts54hub.c index 79c7abd4d..d0c7eb294 100644 --- a/plugins/rts54hub/fu-plugin-rts54hub.c +++ b/plugins/rts54hub/fu-plugin-rts54hub.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); } gboolean diff --git a/plugins/synapticsmst/fu-plugin-synapticsmst.c b/plugins/synapticsmst/fu-plugin-synapticsmst.c index f30b6c7ac..1ceb540d4 100644 --- a/plugins/synapticsmst/fu-plugin-synapticsmst.c +++ b/plugins/synapticsmst/fu-plugin-synapticsmst.c @@ -471,4 +471,5 @@ fu_plugin_init (FuPlugin *plugin) { /* make sure dell is already coldplugged */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "dell"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst"); } diff --git a/plugins/test/fu-plugin-test.c b/plugins/test/fu-plugin-test.c index 2d14c96d3..34023a6d9 100644 --- a/plugins/test/fu-plugin-test.c +++ b/plugins/test/fu-plugin-test.c @@ -15,6 +15,7 @@ struct FuPluginData { void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.acme.test"); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); g_debug ("init"); } diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index c40791cd1..43e1e2c42 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -562,6 +562,7 @@ fu_plugin_init (FuPlugin *plugin) FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); const gchar *subsystems[] = { "thunderbolt", NULL }; + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.intel.thunderbolt"); data->udev = g_udev_client_new (subsystems); g_signal_connect (data->udev, "uevent", G_CALLBACK (udev_uevent_cb), plugin); diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 8d2d3728f..708f0afe1 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -38,6 +38,7 @@ fu_plugin_init (FuPlugin *plugin) FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); data->bgrt = fu_uefi_bgrt_new (); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.uefi.capsule"); fu_plugin_add_compile_version (plugin, "com.redhat.efivar", EFIVAR_LIBRARY_VERSION); } diff --git a/plugins/unifying/fu-plugin-unifying.c b/plugins/unifying/fu-plugin-unifying.c index 6bd35350b..dd9adbcd1 100644 --- a/plugins/unifying/fu-plugin-unifying.c +++ b/plugins/unifying/fu-plugin-unifying.c @@ -174,5 +174,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifying"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifyingsigned"); fu_plugin_add_udev_subsystem (plugin, "hidraw"); } diff --git a/plugins/wacom-usb/fu-plugin-wacom-usb.c b/plugins/wacom-usb/fu-plugin-wacom-usb.c index ed20d5dc1..4617ce482 100644 --- a/plugins/wacom-usb/fu-plugin-wacom-usb.c +++ b/plugins/wacom-usb/fu-plugin-wacom-usb.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.wacom.usb"); } gboolean diff --git a/src/fu-plugin.h b/src/fu-plugin.h index 3b3f042fe..a7655f9db 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -70,6 +70,7 @@ typedef enum { * @FU_PLUGIN_RULE_REQUIRES_QUIRK: Requires a specific quirk * @FU_PLUGIN_RULE_BETTER_THAN: Is better than another plugin * @FU_PLUGIN_RULE_INHIBITS_IDLE: The plugin inhibits the idle shutdown + * @FU_PLUGIN_RULE_SUPPORTS_PROTOCOL: The plugin supports a well known protocol * * The rules used for ordering plugins. * Plugins are expected to add rules in fu_plugin_initialize(). @@ -81,6 +82,7 @@ typedef enum { FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_PLUGIN_RULE_BETTER_THAN, FU_PLUGIN_RULE_INHIBITS_IDLE, + FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, /*< private >*/ FU_PLUGIN_RULE_LAST } FuPluginRule; From adeb2b1b4dfb3e466c37ca229f8f7b46da686b22 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 14 Dec 2018 11:56:41 +0000 Subject: [PATCH 133/254] Add new API to get the release protocol from the metadata --- libfwupd/fwupd-enums-private.h | 3 +- libfwupd/fwupd-release.c | 50 +++++++++++++++++++++++++++++++++- libfwupd/fwupd-release.h | 5 +++- libfwupd/fwupd.map | 7 +++++ src/fu-engine.c | 3 ++ 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index 3eb6eb69c..bb2b9afb3 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 Richard Hughes + * Copyright (C) 2016-2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -14,6 +14,7 @@ #define FWUPD_RESULT_KEY_DEVICE_ID "DeviceId" /* s */ #define FWUPD_RESULT_KEY_PARENT_DEVICE_ID "ParentDeviceId"/* s */ #define FWUPD_RESULT_KEY_FILENAME "Filename" /* s */ +#define FWUPD_RESULT_KEY_PROTOCOL "Protocol" /* s */ #define FWUPD_RESULT_KEY_FLAGS "Flags" /* t */ #define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft" /* u */ #define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index aba345fff..70b998319 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015-2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -33,6 +33,7 @@ typedef struct { GHashTable *metadata; gchar *description; gchar *filename; + gchar *protocol; gchar *homepage; gchar *appstream_id; gchar *license; @@ -158,6 +159,42 @@ fwupd_release_set_filename (FwupdRelease *release, const gchar *filename) priv->filename = g_strdup (filename); } +/** + * fwupd_release_get_protocol: + * @release: A #FwupdRelease + * + * Gets the update protocol. + * + * Returns: the update protocol, or %NULL if unset + * + * Since: 1.2.2 + **/ +const gchar * +fwupd_release_get_protocol (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->protocol; +} + +/** + * fwupd_release_set_protocol: + * @release: A #FwupdRelease + * @protocol: the update protocol, e.g. `org.usb.dfu` + * + * Sets the update protocol. + * + * Since: 1.2.2 + **/ +void +fwupd_release_set_protocol (FwupdRelease *release, const gchar *protocol) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->protocol); + priv->protocol = g_strdup (protocol); +} + /** * fwupd_release_get_checksums: * @release: A #FwupdRelease @@ -739,6 +776,11 @@ fwupd_release_to_variant (FwupdRelease *release) FWUPD_RESULT_KEY_FILENAME, g_variant_new_string (priv->filename)); } + if (priv->protocol != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_PROTOCOL, + g_variant_new_string (priv->protocol)); + } if (priv->license != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_LICENSE, @@ -830,6 +872,10 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant fwupd_release_set_filename (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_PROTOCOL) == 0) { + fwupd_release_set_protocol (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_LICENSE) == 0) { fwupd_release_set_license (release, g_variant_get_string (value, NULL)); return; @@ -968,6 +1014,7 @@ fwupd_release_to_string (FwupdRelease *release) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_FILENAME, priv->filename); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); for (guint i = 0; i < priv->checksums->len; i++) { const gchar *checksum = g_ptr_array_index (priv->checksums, i); g_autofree gchar *checksum_display = fwupd_checksum_format_for_display (checksum); @@ -1015,6 +1062,7 @@ fwupd_release_finalize (GObject *object) g_free (priv->description); g_free (priv->filename); + g_free (priv->protocol); g_free (priv->appstream_id); g_free (priv->license); g_free (priv->name); diff --git a/libfwupd/fwupd-release.h b/libfwupd/fwupd-release.h index 60f6f99ab..4823b8493 100644 --- a/libfwupd/fwupd-release.h +++ b/libfwupd/fwupd-release.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Richard Hughes + * Copyright (C) 2015-2018 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -54,6 +54,9 @@ const gchar *fwupd_release_get_metadata_item (FwupdRelease *release, const gchar *fwupd_release_get_filename (FwupdRelease *release); void fwupd_release_set_filename (FwupdRelease *release, const gchar *filename); +const gchar *fwupd_release_get_protocol (FwupdRelease *release); +void fwupd_release_set_protocol (FwupdRelease *release, + const gchar *protocol); const gchar *fwupd_release_get_appstream_id (FwupdRelease *release); void fwupd_release_set_appstream_id (FwupdRelease *release, const gchar *appstream_id); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 52aba25e7..929764fbd 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -286,3 +286,10 @@ LIBFWUPD_1.2.1 { fwupd_release_set_install_duration; local: *; } LIBFWUPD_1.1.3; + +LIBFWUPD_1.2.2 { + global: + fwupd_release_get_protocol; + fwupd_release_set_protocol; + local: *; +} LIBFWUPD_1.2.1; diff --git a/src/fu-engine.c b/src/fu-engine.c index ef284be4f..fabd10a5d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -321,6 +321,9 @@ fu_engine_set_release_from_appstream (FuEngine *self, tmp64 = xb_node_get_attr_as_uint (release, "install_duration"); if (tmp64 != 0) fwupd_release_set_install_duration (rel, tmp64); + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateProtocol']", NULL); + if (tmp != NULL) + fwupd_release_set_protocol (rel, tmp); } /* finds the remote-id for the first firmware in the silo that matches this From b56015ed3f1da50256ade8d2c89be097298bd5aa Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Dec 2018 09:25:32 +0000 Subject: [PATCH 134/254] uefi: Add the PCR0 value as the device checksum for system firmware We can't actually access the UEFI ROM from userspace, but the PCR0 is a hash built from the ROM itself. We could use this value to ensure the firmware has been written correctly, and that the PCR0 matches the expected value specified in the metadata. --- contrib/PKGBUILD | 1 + contrib/debian/control.in | 2 + contrib/fwupd.spec.in | 1 + plugins/uefi/fu-self-test.c | 69 +++++++++++ plugins/uefi/fu-uefi-device.c | 45 +++++++ plugins/uefi/fu-uefi-pcrs.c | 205 ++++++++++++++++++++++++++++++++ plugins/uefi/fu-uefi-pcrs.h | 23 ++++ plugins/uefi/meson.build | 3 + plugins/uefi/tests/tpm0/active | 1 + plugins/uefi/tests/tpm0/caps | 3 + plugins/uefi/tests/tpm0/enabled | 1 + plugins/uefi/tests/tpm0/owned | 1 + plugins/uefi/tests/tpm0/pcrs | 24 ++++ src/fu-common.c | 6 + src/fu-common.h | 1 + 15 files changed, 386 insertions(+) create mode 100644 plugins/uefi/fu-uefi-pcrs.c create mode 100644 plugins/uefi/fu-uefi-pcrs.h create mode 100644 plugins/uefi/tests/tpm0/active create mode 100644 plugins/uefi/tests/tpm0/caps create mode 100644 plugins/uefi/tests/tpm0/enabled create mode 100644 plugins/uefi/tests/tpm0/owned create mode 100644 plugins/uefi/tests/tpm0/pcrs diff --git a/contrib/PKGBUILD b/contrib/PKGBUILD index 6600a46eb..1b665e90c 100644 --- a/contrib/PKGBUILD +++ b/contrib/PKGBUILD @@ -9,6 +9,7 @@ arch=('i686' 'x86_64') url='https://github.com/hughsie/fwupd' license=('GPL2') depends=('libgusb') +optdepends=('tpm2-abrmd', 'tpm2-tools') makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow' 'git' 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala' 'libsoup' 'polkit' 'gcab') diff --git a/contrib/debian/control.in b/contrib/debian/control.in index 741c3fb8f..94c1cdc3d 100644 --- a/contrib/debian/control.in +++ b/contrib/debian/control.in @@ -33,6 +33,8 @@ Depends: ${misc:Depends}, ${shlibs:Depends} Recommends: python3, bolt, + tpm2-tools, + tpm2-abrmd, fwupd-signed Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index ab55c3b6f..31f9b64ab 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -96,6 +96,7 @@ Requires: bubblewrap Requires: shared-mime-info Recommends: python3 +Recommends: tpm2-tools tpm2-abrmd Obsoletes: fwupd-sign < 0.1.6 Obsoletes: libebitdo < 0.7.5-3 diff --git a/plugins/uefi/fu-self-test.c b/plugins/uefi/fu-self-test.c index bd9c72bb3..da71326a9 100644 --- a/plugins/uefi/fu-self-test.c +++ b/plugins/uefi/fu-self-test.c @@ -13,8 +13,73 @@ #include "fu-uefi-bgrt.h" #include "fu-uefi-common.h" #include "fu-uefi-device.h" +#include "fu-uefi-pcrs.h" #include "fu-uefi-vars.h" +static void +fu_uefi_pcrs_1_2_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_no_error (error); + g_assert_true (ret); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 1); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); +} + +static void +fu_uefi_pcrs_2_0_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + + g_setenv ("FWUPD_UEFI_TPM2_YAML_DATA", + "sha1 :\n" + " 0 : cbd9e4112727bc75761001abcb2dddd87a66caf5\n" + "sha256 :\n" + " 0 : 122de8b579cce17b0703ca9f9716d6f99125af9569e7303f51ea7f85d317f01e\n", TRUE); + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_no_error (error); + g_assert_true (ret); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 2); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); +} + +static void +fu_uefi_pcrs_2_0_failure_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + + g_setenv ("FWUPD_UEFI_TPM2_YAML_DATA", + "Something is not working properly!\n" + "999:hello\n" + "0:dave\n" + "\n", TRUE); + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_assert_false (ret); +} + static void fu_uefi_ucs2_func (void) { @@ -250,11 +315,15 @@ main (int argc, char **argv) g_test_init (&argc, &argv, NULL); g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); g_setenv ("FWUPD_SYSFSDRIVERDIR", TESTDATADIR, TRUE); + g_setenv ("FWUPD_SYSFSTPMDIR", TESTDATADIR, TRUE); /* only critical and error are fatal */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); /* tests go here */ + g_test_add_func ("/uefi/pcrs1.2", fu_uefi_pcrs_1_2_func); + g_test_add_func ("/uefi/pcrs2.0", fu_uefi_pcrs_2_0_func); + g_test_add_func ("/uefi/pcrs2.0{failure}", fu_uefi_pcrs_2_0_failure_func); g_test_add_func ("/uefi/ucs2", fu_uefi_ucs2_func); g_test_add_func ("/uefi/variable", fu_uefi_vars_func); g_test_add_func ("/uefi/bgrt", fu_uefi_bgrt_func); diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index 89ee340b1..ff41e1d47 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -16,6 +16,7 @@ #include "fu-uefi-common.h" #include "fu-uefi-device.h" #include "fu-uefi-bootmgr.h" +#include "fu-uefi-pcrs.h" #include "fu-uefi-vars.h" struct _FuUefiDevice { @@ -429,6 +430,43 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) return TRUE; } +static gboolean +fu_uefi_device_add_system_checksum (FuDevice *device, GError **error) +{ + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + + /* get all the PCRs */ + if (!fu_uefi_pcrs_setup (pcrs, &error_local)) { + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED)) { + g_debug ("%s", error_local->message); + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + + /* get all the PCR0s */ + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + if (pcr0s->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no PCR0s detected"); + return FALSE; + } + for (guint i = 0; i < pcr0s->len; i++) { + const gchar *checksum = g_ptr_array_index (pcr0s, i); + fu_device_add_checksum (device, checksum); + } + + /* success */ + return TRUE; +} + static gboolean fu_uefi_device_probe (FuDevice *device, GError **error) { @@ -476,6 +514,13 @@ fu_uefi_device_probe (FuDevice *device, GError **error) fu_device_add_guid (device, "main-system-firmware"); } + /* set the PCR0 as the device checksum */ + if (self->kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_device_add_system_checksum (device, &error_local)) + g_warning ("Failed to get PCR0s: %s", error_local->message); + } + /* Windows seems to be case insensitive, but for convenience we'll * match the upper case values typically specified in the .inf file */ guid_strup = g_ascii_strup (self->fw_class, -1); diff --git a/plugins/uefi/fu-uefi-pcrs.c b/plugins/uefi/fu-uefi-pcrs.c new file mode 100644 index 000000000..a670e4d0a --- /dev/null +++ b/plugins/uefi/fu-uefi-pcrs.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-pcrs.h" + +typedef struct { + guint idx; + gchar *checksum; +} FuUefiPcrItem; + +struct _FuUefiPcrs { + GObject parent_instance; + GPtrArray *items; /* of FuUefiPcrItem */ +}; + +G_DEFINE_TYPE (FuUefiPcrs, fu_uefi_pcrs, G_TYPE_OBJECT) + +static void +fu_uefi_pcrs_parse_line (const gchar *line, gpointer user_data) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (user_data); + FuUefiPcrItem *item; + guint64 idx; + g_autofree gchar *idxstr = NULL; + g_auto(GStrv) split = NULL; + g_autoptr(GString) str = NULL; + + /* split into index:hash */ + if (line == NULL || line[0] == '\0') + return; + split = g_strsplit (line, ":", 2); + if (g_strv_length (split) != 2) { + g_debug ("unexpected format, skipping: %s", line); + return; + } + + /* get index */ + idxstr = fu_common_strstrip (split[0]); + idx = fu_common_strtoull (idxstr); + if (idx > 64) { + g_debug ("unexpected index, skipping: %s", idxstr); + return; + } + + /* parse hash */ + str = g_string_new (split[1]); + if (str->len < 16) + return; + fu_common_string_replace (str, " ", ""); + g_string_ascii_down (str); + item = g_new0 (FuUefiPcrItem, 1); + item->idx = idx; + item->checksum = g_string_free (g_steal_pointer (&str), FALSE); + g_ptr_array_add (self->items, item); + g_debug ("added PCR-%02u=%s", item->idx, item->checksum); +} + +static gboolean +fu_uefi_pcrs_setup_dummy (FuUefiPcrs *self, const gchar *test_yaml, GError **error) +{ + g_auto(GStrv) lines = g_strsplit (test_yaml, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) + fu_uefi_pcrs_parse_line (lines[i], self); + return TRUE; +} + +static gboolean +fu_uefi_pcrs_setup_tpm12 (FuUefiPcrs *self, const gchar *fn_pcrs, GError **error) +{ + g_auto(GStrv) lines = NULL; + g_autofree gchar *buf_pcrs = NULL; + + /* get entire contents */ + if (!g_file_get_contents (fn_pcrs, &buf_pcrs, NULL, error)) + return FALSE; + + /* find PCR lines */ + lines = g_strsplit (buf_pcrs, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) { + if (g_str_has_prefix (lines[i], "PCR-")) + fu_uefi_pcrs_parse_line (lines[i] + 4, self); + } + return TRUE; +} + +static gboolean +fu_uefi_pcrs_setup_tpm20 (FuUefiPcrs *self, const gchar *argv0, GError **error) +{ + const gchar *argv[] = { argv0, NULL }; + return fu_common_spawn_sync (argv, fu_uefi_pcrs_parse_line, self, NULL, error); +} + +gboolean +fu_uefi_pcrs_setup (FuUefiPcrs *self, GError **error) +{ + g_autofree gchar *devpath = NULL; + g_autofree gchar *sysfstpmdir = NULL; + g_autofree gchar *fn_pcrs = NULL; + const gchar *test_yaml = g_getenv ("FWUPD_UEFI_TPM2_YAML_DATA"); + + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), FALSE); + + /* check the TPM device exists at all */ + sysfstpmdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_TPM); + devpath = g_build_filename (sysfstpmdir, "tpm0", NULL); + if (!g_file_test (devpath, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no TPM device found"); + return FALSE; + } + fn_pcrs = g_build_filename (devpath, "pcrs", NULL); + + /* fake device */ + if (test_yaml != NULL) { + if (!fu_uefi_pcrs_setup_dummy (self, test_yaml, error)) + return FALSE; + + /* look for TPM 1.2 */ + } else if (g_file_test (fn_pcrs, G_FILE_TEST_EXISTS)) { + if (!fu_uefi_pcrs_setup_tpm12 (self, fn_pcrs, error)) + return FALSE; + + /* assume TPM 2.0 */ + } else { + g_autofree gchar *argv0 = NULL; + + /* old name, then new name */ + argv0 = fu_common_find_program_in_path ("tpm2_listpcrs", NULL); + if (argv0 == NULL) + argv0 = fu_common_find_program_in_path ("tpm2_pcrlist", error); + if (argv0 == NULL) + return FALSE; + if (!fu_uefi_pcrs_setup_tpm20 (self, argv0, error)) + return FALSE; + } + + /* check we got anything */ + if (self->items->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no TPMxx measurements found"); + return FALSE; + } + + /* success */ + return TRUE; +} + +GPtrArray * +fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, guint idx) +{ + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), NULL); + for (guint i = 0; i < self->items->len; i++) { + FuUefiPcrItem *item = g_ptr_array_index (self->items, i); + if (item->idx == idx) + g_ptr_array_add (array, g_strdup (item->checksum)); + } + return g_steal_pointer (&array); +} + +static void +fu_uefi_pcrs_item_free (FuUefiPcrItem *item) +{ + g_free (item->checksum); + g_free (item); +} + +static void +fu_uefi_pcrs_finalize (GObject *object) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (object); + g_ptr_array_unref (self->items); + G_OBJECT_CLASS (fu_uefi_pcrs_parent_class)->finalize (object); +} + +static void +fu_uefi_pcrs_class_init (FuUefiPcrsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_pcrs_finalize; +} + +static void +fu_uefi_pcrs_init (FuUefiPcrs *self) +{ + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_pcrs_item_free); +} + +FuUefiPcrs * +fu_uefi_pcrs_new (void) +{ + FuUefiPcrs *self; + self = g_object_new (FU_TYPE_UEFI_PCRS, NULL); + return FU_UEFI_PCRS (self); +} diff --git a/plugins/uefi/fu-uefi-pcrs.h b/plugins/uefi/fu-uefi-pcrs.h new file mode 100644 index 000000000..9837a9add --- /dev/null +++ b/plugins/uefi/fu-uefi-pcrs.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_UEFI_PCRS_H +#define __FU_UEFI_PCRS_H + +G_BEGIN_DECLS + +#define FU_TYPE_UEFI_PCRS (fu_uefi_pcrs_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiPcrs, fu_uefi_pcrs, FU, UEFI_PCRS, GObject) + +FuUefiPcrs *fu_uefi_pcrs_new (void); +gboolean fu_uefi_pcrs_setup (FuUefiPcrs *self, + GError **error); +GPtrArray *fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, + guint idx); + +G_END_DECLS + +#endif /* __FU_UEFI_PCRS_H */ diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index c037e1b30..575f6c64e 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -15,6 +15,7 @@ shared_module('fu_plugin_uefi', 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', 'fu-uefi-vars.c', ], @@ -43,6 +44,7 @@ executable( 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', 'fu-uefi-vars.c', ], @@ -83,6 +85,7 @@ if get_option('tests') 'fu-uefi-bootmgr.c', 'fu-uefi-common.c', 'fu-uefi-device.c', + 'fu-uefi-pcrs.c', 'fu-uefi-update-info.c', 'fu-uefi-vars.c', 'fu-ucs2.c', diff --git a/plugins/uefi/tests/tpm0/active b/plugins/uefi/tests/tpm0/active new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/plugins/uefi/tests/tpm0/active @@ -0,0 +1 @@ +1 diff --git a/plugins/uefi/tests/tpm0/caps b/plugins/uefi/tests/tpm0/caps new file mode 100644 index 000000000..af0d3cb00 --- /dev/null +++ b/plugins/uefi/tests/tpm0/caps @@ -0,0 +1,3 @@ +Manufacturer: 0x49465800 +TCG version: 1.2 +Firmware version: 6.40 diff --git a/plugins/uefi/tests/tpm0/enabled b/plugins/uefi/tests/tpm0/enabled new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/plugins/uefi/tests/tpm0/enabled @@ -0,0 +1 @@ +1 diff --git a/plugins/uefi/tests/tpm0/owned b/plugins/uefi/tests/tpm0/owned new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/plugins/uefi/tests/tpm0/owned @@ -0,0 +1 @@ +1 diff --git a/plugins/uefi/tests/tpm0/pcrs b/plugins/uefi/tests/tpm0/pcrs new file mode 100644 index 000000000..004e69048 --- /dev/null +++ b/plugins/uefi/tests/tpm0/pcrs @@ -0,0 +1,24 @@ +PCR-00: 3C 97 99 20 C9 00 99 60 09 27 D5 DA B3 81 EB 95 1E 7F C8 68 +PCR-01: CE 9F A4 B2 01 09 D8 81 14 EA 1A 6D 13 94 CD 45 5F 52 69 23 +PCR-02: 47 09 7A 9A AD C3 26 A4 93 91 26 63 A1 6F DF 53 D7 88 96 8E +PCR-03: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-04: A4 A5 87 4C 59 94 8D 9B 93 66 0A F4 19 D8 6F F8 94 36 20 CC +PCR-05: 00 0B 58 00 89 72 EF 6C 2A AC 79 33 C4 AE 67 6B A6 EF CF 6A +PCR-06: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-07: 0A 2A 68 15 85 0D AC B2 D1 F4 E0 C1 F4 56 D5 E2 81 08 6D EA +PCR-08: DB A7 29 4E 49 BA D7 9E 53 99 0A 6E 3A CB 52 97 B9 08 3A 66 +PCR-09: 19 F9 6F 10 83 F5 5B 50 98 26 C3 14 73 43 35 21 1F E6 39 E9 +PCR-10: 37 3D 89 9E 10 0D DD 2D 21 B5 F4 96 8D 4F DC A7 6D 1A C7 BD +PCR-11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff --git a/src/fu-common.c b/src/fu-common.c index e7117e30e..b567a73ab 100644 --- a/src/fu-common.c +++ b/src/fu-common.c @@ -928,6 +928,12 @@ fu_common_get_path (FuPathKind path_kind) if (tmp != NULL) return g_strdup (tmp); return g_strdup ("/sys/firmware"); + /* /sys/firmware */ + case FU_PATH_KIND_SYSFSDIR_TPM: + tmp = g_getenv ("FWUPD_SYSFSTPMDIR"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/sys/class/tpm"); /* /sys/bus/platform/drivers */ case FU_PATH_KIND_SYSFSDIR_DRIVERS: tmp = g_getenv ("FWUPD_SYSFSDRIVERDIR"); diff --git a/src/fu-common.h b/src/fu-common.h index 69b0a88f5..cfce057ea 100644 --- a/src/fu-common.h +++ b/src/fu-common.h @@ -26,6 +26,7 @@ typedef enum { FU_PATH_KIND_SYSCONFDIR_PKG, FU_PATH_KIND_SYSFSDIR_FW, FU_PATH_KIND_SYSFSDIR_DRIVERS, + FU_PATH_KIND_SYSFSDIR_TPM, FU_PATH_KIND_LAST } FuPathKind; From 4e886a4dfa952673d5be380850b461fec8b425e9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Dec 2018 10:33:26 +0000 Subject: [PATCH 135/254] Include the device checksum and update protocol in the historydb --- src/fu-engine.c | 8 +++++ src/fu-history.c | 78 +++++++++++++++++++++++++++++++++++++++++----- src/fu-self-test.c | 1 + 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index fabd10a5d..d384d757d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -3657,9 +3657,17 @@ fu_engine_update_history_device (FuEngine *self, FuDevice *dev_history, GError * /* the system is running with the new firmware version */ if (g_strcmp0 (fu_device_get_version (dev), fwupd_release_get_version (rel_history)) == 0) { + GPtrArray *checksums; g_debug ("installed version %s matching history %s", fu_device_get_version (dev), fwupd_release_get_version (rel_history)); + + /* copy over runtime checksums if set from probe() */ + checksums = fu_device_get_checksums (dev); + for (guint i = 0; i < checksums->len; i++) { + const gchar *csum = g_ptr_array_index (checksums, i); + fu_device_add_checksum (dev_history, csum); + } fu_device_set_update_state (dev_history, FWUPD_UPDATE_STATE_SUCCESS); return fu_history_modify_device (self->history, dev_history, FU_HISTORY_FLAGS_MATCH_NEW_VERSION, diff --git a/src/fu-history.c b/src/fu-history.c index d6b0a18bb..0f90e0114 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -113,6 +113,16 @@ fu_history_device_from_stmt (sqlite3_stmt *stmt) tmp = (const gchar *) sqlite3_column_text (stmt, 13); if (tmp != NULL) fu_device_set_version (device, tmp); + + /* checksum_device */ + tmp = (const gchar *) sqlite3_column_text (stmt, 14); + if (tmp != NULL) + fu_device_add_checksum (device, tmp); + + /* protocol */ + tmp = (const gchar *) sqlite3_column_text (stmt, 15); + if (tmp != NULL) + fwupd_release_set_protocol (release, tmp); return device; } @@ -147,7 +157,7 @@ fu_history_create_database (FuHistory *self, GError **error) "CREATE TABLE schema (" "created timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP," "version INTEGER DEFAULT 0);" - "INSERT INTO schema (version) VALUES (2);" + "INSERT INTO schema (version) VALUES (3);" "CREATE TABLE history (" "device_id TEXT," "update_state INTEGER DEFAULT 0," @@ -162,7 +172,9 @@ fu_history_create_database (FuHistory *self, GError **error) "metadata TEXT DEFAULT NULL," "guid_default TEXT DEFAULT NULL," "version_old TEXT," - "version_new TEXT);" + "version_new TEXT," + "checksum_device TEXT DEFAULT NULL," + "protocol TEXT DEFAULT NULL);" "COMMIT;", NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -193,7 +205,11 @@ fu_history_migrate_database_v1 (FuHistory *self, GError **error) /* migrate the old entries to the new table */ rc = sqlite3_exec (self->db, - "INSERT INTO history SELECT * FROM history_old;" + "INSERT INTO history SELECT " + "device_id, update_state, update_error, filename, " + "display_name, plugin, device_created, device_modified, " + "checksum, flags, metadata, guid_default, version_old, " + "version_new, NULL, NULL FROM history_old;" "DROP TABLE history_old;", NULL, NULL, NULL); if (rc != SQLITE_OK) { @@ -203,6 +219,33 @@ fu_history_migrate_database_v1 (FuHistory *self, GError **error) return TRUE; } +static gboolean +fu_history_migrate_database_v2 (FuHistory *self, GError **error) +{ + gint rc; + + /* rename the table to something out the way */ + rc = sqlite3_exec (self->db, + "ALTER TABLE history ADD COLUMN checksum_device TEXT DEFAULT NULL;", + NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to alter database: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + + /* update version */ + rc = sqlite3_exec (self->db, "UPDATE schema SET version=3;", NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to migrate database: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + /* returns 0 if database is not initialised */ static guint fu_history_get_schema_version (FuHistory *self) @@ -286,6 +329,10 @@ fu_history_load (FuHistory *self, GError **error) g_debug ("migrating v%u database", schema_ver); if (!fu_history_migrate_database_v1 (self, error)) return FALSE; + } else if (schema_ver == 2) { + g_debug ("migrating v%u database", schema_ver); + if (!fu_history_migrate_database_v2 (self, error)) + return FALSE; } return TRUE; @@ -344,6 +391,7 @@ fu_history_modify_device (FuHistory *self, FuDevice *device, "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4;", -1, &stmt, NULL); @@ -356,6 +404,7 @@ fu_history_modify_device (FuHistory *self, FuDevice *device, "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4 AND version_old = ?5;", -1, &stmt, NULL); @@ -368,6 +417,7 @@ fu_history_modify_device (FuHistory *self, FuDevice *device, "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4 AND version_new = ?5;", -1, &stmt, NULL); @@ -380,17 +430,21 @@ fu_history_modify_device (FuHistory *self, FuDevice *device, sqlite3_errmsg (self->db)); return FALSE; } + sqlite3_bind_int (stmt, 1, fu_device_get_update_state (device)); sqlite3_bind_text (stmt, 2, fu_device_get_update_error (device), -1, SQLITE_STATIC); sqlite3_bind_int64 (stmt, 3, fu_history_get_device_flags_filtered (device)); sqlite3_bind_text (stmt, 4, fu_device_get_id (device), -1, SQLITE_STATIC); sqlite3_bind_text (stmt, 5, fu_device_get_version (device), -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 6, fwupd_checksum_get_by_kind (fu_device_get_checksums (device), + G_CHECKSUM_SHA1), -1, SQLITE_STATIC); return fu_history_stmt_exec (self, stmt, NULL, error); } gboolean fu_history_add_device (FuHistory *self, FuDevice *device, FwupdRelease *release, GError **error) { + const gchar *checksum_device; const gchar *checksum = NULL; gint rc; g_autofree gchar *metadata = NULL; @@ -416,6 +470,8 @@ fu_history_add_device (FuHistory *self, FuDevice *device, FwupdRelease *release, GPtrArray *checksums = fwupd_release_get_checksums (release); checksum = fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1); } + checksum_device = fwupd_checksum_get_by_kind (fu_device_get_checksums (device), + G_CHECKSUM_SHA1); /* metadata is stored as a simple string */ metadata = _convert_hash_to_string (fwupd_release_get_metadata (release)); @@ -437,9 +493,11 @@ fu_history_add_device (FuHistory *self, FuDevice *device, FwupdRelease *release, "device_created," "device_modified," "version_old," - "version_new) " + "version_new," + "checksum_device," + "protocol) " "VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10," - "?11,?12,?13,?14)", -1, &stmt, NULL); + "?11,?12,?13,?14,?15,?16)", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Failed to prepare SQL: %s", @@ -460,6 +518,8 @@ fu_history_add_device (FuHistory *self, FuDevice *device, FwupdRelease *release, sqlite3_bind_int64 (stmt, 12, fu_device_get_modified (device)); sqlite3_bind_text (stmt, 13, fu_device_get_version (device), -1, SQLITE_STATIC); sqlite3_bind_text (stmt, 14, fwupd_release_get_version (release), -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 15, checksum_device, -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 16, fwupd_release_get_protocol (release), -1, SQLITE_STATIC); return fu_history_stmt_exec (self, stmt, NULL, error); } @@ -594,7 +654,9 @@ fu_history_get_device_by_id (FuHistory *self, const gchar *device_id, GError **e "update_state, " "update_error, " "version_new, " - "version_old FROM history WHERE " + "version_old, " + "checksum_device, " + "protocol FROM history WHERE " "device_id = ?1 LIMIT 1", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -650,7 +712,9 @@ fu_history_get_devices (FuHistory *self, GError **error) "update_state, " "update_error, " "version_new, " - "version_old FROM history " + "version_old, " + "checksum_device, " + "protocol FROM history " "ORDER BY device_modified ASC;", -1, &stmt, NULL); if (rc != SQLITE_OK) { diff --git a/src/fu-self-test.c b/src/fu-self-test.c index d57ef8949..090d46375 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -874,6 +874,7 @@ fu_engine_history_func (void) fu_device_set_name (device, "Test Device"); fu_device_set_plugin (device, "test"); fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_add_checksum (device, "0123456789abcdef0123456789abcdef01234567"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_created (device, 1515338000); fu_engine_add_device (engine, device); From 1812fc783bd9263087038f0e8146530baeb11a20 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 14 Dec 2018 11:37:54 +0000 Subject: [PATCH 136/254] trivial: Clear the device checksums only if the plugin implements verify() This ensures that plugins that set the checksums in probe() or setup() don't get erased by accident. --- src/fu-plugin.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fu-plugin.c b/src/fu-plugin.c index 7cd8ffc74..f08bb279e 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -1384,14 +1384,16 @@ fu_plugin_runner_verify (FuPlugin *self, if (priv->module == NULL) return TRUE; - /* clear any existing verification checksums */ - checksums = fu_device_get_checksums (device); - g_ptr_array_set_size (checksums, 0); - /* optional */ g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func); if (func == NULL) return TRUE; + + /* clear any existing verification checksums */ + checksums = fu_device_get_checksums (device); + g_ptr_array_set_size (checksums, 0); + + /* run vfunc */ g_debug ("performing verify() on %s", priv->name); if (!func (self, device, flags, &error_local)) { if (error_local == NULL) { From 08435169a7f40cc949c905622864527e332ec54b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Dec 2018 10:34:16 +0000 Subject: [PATCH 137/254] trivial: Don't invalidate the current checksums for fw that requries a reboot --- src/fu-plugin.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fu-plugin.c b/src/fu-plugin.c index f08bb279e..9c4382f4f 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -1453,7 +1453,6 @@ fu_plugin_runner_update (FuPlugin *self, g_autoptr(FuHistory) history = NULL; g_autoptr(FuDevice) device_pending = NULL; g_autoptr(GError) error_local = NULL; - GPtrArray *checksums; /* not enabled */ if (!priv->enabled) { @@ -1515,8 +1514,10 @@ fu_plugin_runner_update (FuPlugin *self, } /* no longer valid */ - checksums = fu_device_get_checksums (device); - g_ptr_array_set_size (checksums, 0); + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) { + GPtrArray *checksums = fu_device_get_checksums (device); + g_ptr_array_set_size (checksums, 0); + } /* cleanup */ if (device_pending != NULL) { From e2fa12ed2f11b7136bc49fd112b86dd81d42616d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Dec 2018 10:38:10 +0000 Subject: [PATCH 138/254] Submit the device firmware checksum and update protocol in the submitted report This is usually the same as the content checksum, but can be a different value for instance in the PCR0 UEFI case. --- libfwupd/fwupd-common.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index 8e52bbb87..4578c3fe8 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -352,12 +352,27 @@ fwupd_build_history_report_json_device (JsonBuilder *builder, FwupdDevice *dev) { FwupdRelease *rel = fwupd_device_get_release_default (dev); GPtrArray *checksums; + const gchar *tmp; /* identify the firmware used */ json_builder_set_member_name (builder, "Checksum"); checksums = fwupd_release_get_checksums (rel); json_builder_add_string_value (builder, fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1)); + /* identify the firmware written */ + checksums = fwupd_device_get_checksums (dev); + tmp = fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1); + if (tmp != NULL) { + json_builder_set_member_name (builder, "ChecksumDevice"); + json_builder_add_string_value (builder, tmp); + } + + /* include the protocol used */ + if (fwupd_release_get_protocol (rel) != NULL) { + json_builder_set_member_name (builder, "Protocol"); + json_builder_add_string_value (builder, fwupd_release_get_protocol (rel)); + } + /* set the error state of the report */ json_builder_set_member_name (builder, "UpdateState"); json_builder_add_int_value (builder, fwupd_device_get_update_state (dev)); From 45bbfc9cae0928fc06c422e64db9d1f2add2f151 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 12 Dec 2018 10:57:08 +0000 Subject: [PATCH 139/254] Check the device checksum as well as the content checksum during verify Some firmware has a different on-device checksum to the hash of the firmware file itself. This may be because: * The content is not a binary file, e.g. Intel HEX or SREC * Only part of the firmware is flashed, e.g. ignoring the bootloader section * The device checksum is calculated using another method entirely, e.g. PCR0 It's also made complicated as there may be more than one 'correct' device checksum in some cases, but nothing that a union query can't solve. --- contrib/PKGBUILD | 2 +- src/fu-engine.c | 65 +++++++++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/contrib/PKGBUILD b/contrib/PKGBUILD index 1b665e90c..e004c72d5 100644 --- a/contrib/PKGBUILD +++ b/contrib/PKGBUILD @@ -9,7 +9,7 @@ arch=('i686' 'x86_64') url='https://github.com/hughsie/fwupd' license=('GPL2') depends=('libgusb') -optdepends=('tpm2-abrmd', 'tpm2-tools') +optdepends=('tpm2-abrmd' 'tpm2-tools') makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow' 'git' 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala' 'libsoup' 'polkit' 'gcab') diff --git a/src/fu-engine.c b/src/fu-engine.c index d384d757d..9363fb394 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -653,12 +653,12 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) { FuPlugin *plugin; GPtrArray *checksums; - const gchar *hash = NULL; const gchar *version; g_autofree gchar *fn = NULL; g_autofree gchar *localstatedir = NULL; g_autoptr(FuDevice) device = NULL; g_autoptr(GFile) file = NULL; + g_autoptr(GString) xpath_csum = g_string_new (NULL); g_autoptr(XbNode) csum = NULL; g_autoptr(XbNode) release = NULL; g_autoptr(XbSilo) silo = xb_silo_new (); @@ -730,16 +730,6 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) return FALSE; } - /* find checksum */ - csum = xb_node_query_first (release, "checksum[@target='content']", NULL); - if (csum == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No content checksum for %s", version); - return FALSE; - } - /* get the matching checksum */ checksums = fu_device_get_checksums (device); if (checksums->len == 0) { @@ -749,29 +739,52 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) "No device checksums for %s", version); return FALSE; } + + /* do any of the checksums in the release match any in the device */ for (guint j = 0; j < checksums->len; j++) { const gchar *hash_tmp = g_ptr_array_index (checksums, j); - GChecksumType hash_kind = fwupd_checksum_guess_kind (hash_tmp); - if (fwupd_checksum_guess_kind (xb_node_get_text (csum)) == hash_kind) { - hash = hash_tmp; - break; + xb_string_append_union (xpath_csum, + "checksum[@target='device'][text()='%s']", + hash_tmp); + xb_string_append_union (xpath_csum, + "checksum[@target='content'][text()='%s']", + hash_tmp); + } + csum = xb_node_query_first (release, xpath_csum->str, NULL); + if (csum == NULL) { + g_autoptr(GString) checksums_device = g_string_new (NULL); + g_autoptr(GString) checksums_metadata = g_string_new (NULL); + g_autoptr(GPtrArray) csums = NULL; + g_autoptr(GString) xpath = g_string_new (NULL); + + /* get all checksums to display a useful error */ + xb_string_append_union (xpath, "checksum[@target='device']"); + xb_string_append_union (xpath, "checksum[@target='content']"); + csums = xb_node_query (release, xpath->str, 0, NULL); + if (csums == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No device or content checksum for %s", + version); + return FALSE; + } + for (guint i = 0; i < csums->len; i++) { + XbNode *csum_tmp = g_ptr_array_index (csums, i); + xb_string_append_union (checksums_metadata, + "%s", xb_node_get_text (csum_tmp)); + } + for (guint i = 0; i < checksums->len; i++) { + const gchar *hash_tmp = g_ptr_array_index (checksums, i); + xb_string_append_union (checksums_device, "%s", hash_tmp); } - } - if (hash == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No matching hash kind for %s", version); - return FALSE; - } - if (g_strcmp0 (xb_node_get_text (csum), hash) != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "For v%s expected %s, got %s", version, - xb_node_get_text (csum), - hash); + checksums_metadata->str, + checksums_device->str); return FALSE; } From 60552008224aebfc4b4e633fe23d9e8403dc9db2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Dec 2018 08:33:10 +0000 Subject: [PATCH 140/254] trivial: Check the GUID length before attempting to parse it It seems uuid_parse() doesn't check the string length before unwrapping the string into a struct. Fixes: Conditional jump or move depends on uninitialised value(s) at 0x4E0C358: uuid_is_null (isnull.c:44) --- src/fu-common-guid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fu-common-guid.c b/src/fu-common-guid.c index 8ec036eb1..088ddb4ed 100644 --- a/src/fu-common-guid.c +++ b/src/fu-common-guid.c @@ -96,6 +96,8 @@ fu_common_guid_is_valid (const gchar *guid) uuid_t uu; if (guid == NULL) return FALSE; + if (strlen (guid) != 36) + return FALSE; rc = uuid_parse (guid, uu); if (uuid_is_null (uu)) return FALSE; From 9d6dc95f41afc79492ac6c49f1ae3b93e4302fc3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Dec 2018 08:34:06 +0000 Subject: [PATCH 141/254] trivial: Fix a memory leak if dfu-tool returns with an error --- plugins/dfu/dfu-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index e9c7e2dc0..28e3264a6 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -49,6 +49,7 @@ dfu_tool_private_free (DfuToolPrivate *priv) if (priv == NULL) return; g_free (priv->device_vid_pid); + g_object_unref (priv->progressbar); g_object_unref (priv->cancellable); g_object_unref (priv->quirks); if (priv->cmd_array != NULL) @@ -2426,6 +2427,5 @@ main (int argc, char *argv[]) } /* success/ */ - g_object_unref (priv->progressbar); return EXIT_SUCCESS; } From 8d026128938b0ad8fcc351c16e29bdfb86e83a5e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Dec 2018 08:34:27 +0000 Subject: [PATCH 142/254] trivial: Fix an error code if a search string is unfound --- plugins/dfu/dfu-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index 28e3264a6..a64e52099 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -675,7 +675,7 @@ dfu_tool_replace_data (DfuToolPrivate *priv, gchar **values, GError **error) if (cnt == 0) { g_set_error_literal (error, FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, + FWUPD_ERROR_NOT_FOUND, "search string was not found"); return FALSE; } From 420ccd46fabce5e2094d81bebff7101a18f69d7f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Dec 2018 08:35:18 +0000 Subject: [PATCH 143/254] Allow replacing the last byte in the image when using 'dfu-tool replace-data' Fixes https://github.com/hughsie/fwupd/issues/903 --- plugins/dfu/dfu-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dfu/dfu-tool.c b/plugins/dfu/dfu-tool.c index a64e52099..196415f47 100644 --- a/plugins/dfu/dfu-tool.c +++ b/plugins/dfu/dfu-tool.c @@ -480,7 +480,7 @@ dfu_tool_bytes_replace (GBytes *data, GBytes *search, GBytes *replace) g_return_val_if_fail (search_sz == replace_sz, FALSE); /* find and replace each one */ - for (gsize i = 0; i < data_sz - search_sz; i++) { + for (gsize i = 0; i < data_sz - search_sz + 1; i++) { if (memcmp (data_buf + i, search_buf, search_sz) == 0) { g_print ("Replacing %" G_GSIZE_FORMAT " bytes @0x%04x\n", replace_sz, (guint) i); From 319dbcba5c4cc3b063bd1dfaf700b22c529a4291 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Dec 2018 17:59:05 +0000 Subject: [PATCH 144/254] trivial: Don't show 'Update Duration: 49710 days' Use the correct 'value not found' constant for xb_node_get_attr_as_uint(). --- src/fu-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 9363fb394..f5df88ba1 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -319,7 +319,7 @@ fu_engine_set_release_from_appstream (FuEngine *self, } } tmp64 = xb_node_get_attr_as_uint (release, "install_duration"); - if (tmp64 != 0) + if (tmp64 != G_MAXUINT64) fwupd_release_set_install_duration (rel, tmp64); tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateProtocol']", NULL); if (tmp != NULL) From 7f59a6f84443ee305f40ffdb696faaa18d88ee92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20M=C3=A1rton?= Date: Mon, 17 Dec 2018 13:41:23 +0100 Subject: [PATCH 145/254] Add Dell TB18DC to the known devices list --- plugins/synapticsmst/README.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/plugins/synapticsmst/README.md b/plugins/synapticsmst/README.md index b5206e8dd..5b1e3ea0a 100644 --- a/plugins/synapticsmst/README.md +++ b/plugins/synapticsmst/README.md @@ -57,18 +57,19 @@ Payloads can be flashed just like any other plugin from LVFS. ## Supported devices Not all Dell systems or accessories contain MST hubs. Here is a sample list of systems known to support them however: -1. Dell WD15 dock -2. Dell TB16 dock -3. Latitude E5570 -4. Latitude E5470 -5. Latitude E5270 -6. Latitude E7470 -7. Latitude E7270 -8. Latitude E7450 -9. Latitude E7250 -10. Latitude E5550 -11. Latitude E5450 -12. Latitude E5250 -13. Latitude Rugged 5414 -14. Latitude Rugged 7214 -15. Latitude Rugged 7414 + * Dell WD15 dock + * Dell TB16 dock + * Dell TB18DC + * Latitude E5570 + * Latitude E5470 + * Latitude E5270 + * Latitude E7470 + * Latitude E7270 + * Latitude E7450 + * Latitude E7250 + * Latitude E5550 + * Latitude E5450 + * Latitude E5250 + * Latitude Rugged 5414 + * Latitude Rugged 7214 + * Latitude Rugged 7414 From 363127e51884af4654f74d3dc671e82e9bc26220 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 20 Dec 2018 09:49:11 +0000 Subject: [PATCH 146/254] ebitdo: Fix the reported version number if the daemon locale is not C.UTF-8 Always use a dot as the delimiter of a semver rather than treating it as a floating point number. Related to https://github.com/hughsie/lvfs-website/issues/216 --- plugins/ebitdo/fu-ebitdo-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ebitdo/fu-ebitdo-device.c b/plugins/ebitdo/fu-ebitdo-device.c index 25e1ddd8e..42cacfa98 100644 --- a/plugins/ebitdo/fu-ebitdo-device.c +++ b/plugins/ebitdo/fu-ebitdo-device.c @@ -215,7 +215,7 @@ static void fu_ebitdo_device_set_version (FuEbitdoDevice *self, guint32 version) { g_autofree gchar *tmp = NULL; - tmp = g_strdup_printf ("%.2f", version / 100.f); + tmp = g_strdup_printf ("%u.%02u", version / 100, version % 100); fu_device_set_version (FU_DEVICE (self), tmp); } From 0e17e6d03071f4c4986e1baf7ecf6d5736f4144c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 22 Dec 2018 12:11:33 +0000 Subject: [PATCH 147/254] Fix building with -Wl,-z,defs This allows us to find undefined references at compile time, not runtime. --- meson.build | 1 + plugins/altos/meson.build | 3 +++ plugins/amt/meson.build | 3 +++ plugins/colorhug/meson.build | 3 +++ plugins/csr/meson.build | 1 + plugins/dell-dock/meson.build | 3 +++ plugins/dell-esrt/meson.build | 7 +++++-- plugins/dell/meson.build | 8 +++++--- plugins/dfu/meson.build | 6 ++++-- plugins/ebitdo/meson.build | 3 +++ plugins/fastboot/meson.build | 3 +++ plugins/flashrom/meson.build | 3 +++ plugins/nitrokey/meson.build | 3 +++ plugins/nvme/meson.build | 4 +++- plugins/redfish/meson.build | 4 +++- plugins/rts54hid/meson.build | 3 +++ plugins/rts54hub/meson.build | 3 +++ plugins/steelseries/meson.build | 3 +++ plugins/superio/meson.build | 3 +++ plugins/synapticsmst/meson.build | 8 +++++--- plugins/test/meson.build | 3 +++ plugins/thunderbolt-power/meson.build | 3 +++ plugins/thunderbolt/meson.build | 5 +++-- plugins/udev/meson.build | 5 +++-- plugins/uefi/meson.build | 5 +++-- plugins/unifying/meson.build | 5 ++++- plugins/upower/meson.build | 3 +++ plugins/wacom-usb/meson.build | 2 +- src/meson.build | 3 +++ 29 files changed, 89 insertions(+), 20 deletions(-) diff --git a/meson.build b/meson.build index 6a12c4b94..b3bcd6718 100644 --- a/meson.build +++ b/meson.build @@ -111,6 +111,7 @@ add_project_arguments(cc.get_supported_arguments(warning_flags), language : 'c') global_link_args = [] test_link_args = [ '-Wl,-z,relro', + '-Wl,-z,defs', '-Wl,-z,now', ] foreach arg: test_link_args diff --git a/plugins/altos/meson.build b/plugins/altos/meson.build index eb0300b96..bd0d8e47c 100644 --- a/plugins/altos/meson.build +++ b/plugins/altos/meson.build @@ -17,6 +17,9 @@ shared_module('fu_plugin_altos', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ libelf, diff --git a/plugins/amt/meson.build b/plugins/amt/meson.build index b3711974d..18ddedb35 100644 --- a/plugins/amt/meson.build +++ b/plugins/amt/meson.build @@ -11,6 +11,9 @@ shared_module('fu_plugin_amt', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/colorhug/meson.build b/plugins/colorhug/meson.build index 206e71497..3b6b86279 100644 --- a/plugins/colorhug/meson.build +++ b/plugins/colorhug/meson.build @@ -19,6 +19,9 @@ shared_module('fu_plugin_colorhug', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/csr/meson.build b/plugins/csr/meson.build index 401283b20..3748c18e3 100644 --- a/plugins/csr/meson.build +++ b/plugins/csr/meson.build @@ -22,6 +22,7 @@ shared_module('fu_plugin_csr', plugin_deps, ], link_with : [ + libfwupdprivate, dfu, ], ) diff --git a/plugins/dell-dock/meson.build b/plugins/dell-dock/meson.build index 214420b50..a03a60760 100644 --- a/plugins/dell-dock/meson.build +++ b/plugins/dell-dock/meson.build @@ -21,6 +21,9 @@ shared_module('fu_plugin_dell_dock', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/dell-esrt/meson.build b/plugins/dell-esrt/meson.build index 76da59ea4..39fae22d3 100644 --- a/plugins/dell-esrt/meson.build +++ b/plugins/dell-esrt/meson.build @@ -12,8 +12,11 @@ shared_module('fu_plugin_dell_esrt', install : true, install_dir: plugin_dir, c_args : [ - cargs, - ], + cargs, + ], + link_with : [ + libfwupdprivate, + ], dependencies : [ plugin_deps, libsmbios_c, diff --git a/plugins/dell/meson.build b/plugins/dell/meson.build index 0a0dcc5df..67683591b 100644 --- a/plugins/dell/meson.build +++ b/plugins/dell/meson.build @@ -16,9 +16,12 @@ shared_module('fu_plugin_dell', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : [ - cargs, - ], + cargs, + ], dependencies : [ plugin_deps, efivar, @@ -51,7 +54,6 @@ if get_option('tests') valgrind, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : [ diff --git a/plugins/dfu/meson.build b/plugins/dfu/meson.build index cac1a82b1..404b7bbb7 100644 --- a/plugins/dfu/meson.build +++ b/plugins/dfu/meson.build @@ -31,6 +31,9 @@ dfu = static_library( gusb, gudev, ], + link_with : [ + libfwupdprivate, + ], c_args : cargs, include_directories : [ include_directories('../..'), @@ -55,6 +58,7 @@ shared_module('fu_plugin_dfu', plugin_deps, ], link_with : [ + libfwupdprivate, dfu, ], ) @@ -79,7 +83,6 @@ dfu_tool = executable( ], link_with : [ dfu, - fwupd, libfwupdprivate, ], c_args : cargs, @@ -130,7 +133,6 @@ if get_option('tests') ], link_with : [ dfu, - fwupd, libfwupdprivate, ], c_args : cargs diff --git a/plugins/ebitdo/meson.build b/plugins/ebitdo/meson.build index a952bae21..4d438a740 100644 --- a/plugins/ebitdo/meson.build +++ b/plugins/ebitdo/meson.build @@ -17,6 +17,9 @@ shared_module('fu_plugin_ebitdo', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/fastboot/meson.build b/plugins/fastboot/meson.build index 4042e5310..3afa16734 100644 --- a/plugins/fastboot/meson.build +++ b/plugins/fastboot/meson.build @@ -16,6 +16,9 @@ shared_module('fu_plugin_fastboot', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/flashrom/meson.build b/plugins/flashrom/meson.build index 1b4250f03..ee048e51f 100644 --- a/plugins/flashrom/meson.build +++ b/plugins/flashrom/meson.build @@ -15,6 +15,9 @@ shared_module('fu_plugin_flashrom', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : [ cargs, '-DLOCALSTATEDIR="' + localstatedir + '"', diff --git a/plugins/nitrokey/meson.build b/plugins/nitrokey/meson.build index 324958fc6..1aee68859 100644 --- a/plugins/nitrokey/meson.build +++ b/plugins/nitrokey/meson.build @@ -17,6 +17,9 @@ shared_module('fu_plugin_nitrokey', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/nvme/meson.build b/plugins/nvme/meson.build index bc5d28137..a3af4638b 100644 --- a/plugins/nvme/meson.build +++ b/plugins/nvme/meson.build @@ -16,6 +16,9 @@ shared_module('fu_plugin_nvme', cargs, '-DLOCALSTATEDIR="' + localstatedir + '"', ], + link_with : [ + libfwupdprivate, + ], dependencies : [ plugin_deps, efivar, @@ -42,7 +45,6 @@ if get_option('tests') efivar, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff --git a/plugins/redfish/meson.build b/plugins/redfish/meson.build index 288f614e4..ef07bd819 100644 --- a/plugins/redfish/meson.build +++ b/plugins/redfish/meson.build @@ -13,6 +13,9 @@ shared_module('fu_plugin_redfish', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -44,7 +47,6 @@ if get_option('tests') libjsonglib, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff --git a/plugins/rts54hid/meson.build b/plugins/rts54hid/meson.build index 517dde396..ff6c621de 100644 --- a/plugins/rts54hid/meson.build +++ b/plugins/rts54hid/meson.build @@ -19,6 +19,9 @@ shared_module('fu_plugin_rts54hid', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/rts54hub/meson.build b/plugins/rts54hub/meson.build index a046af90a..3f525b4ad 100644 --- a/plugins/rts54hub/meson.build +++ b/plugins/rts54hub/meson.build @@ -18,6 +18,9 @@ shared_module('fu_plugin_rts54hub', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/steelseries/meson.build b/plugins/steelseries/meson.build index cf4fd3342..e2fc45ea5 100644 --- a/plugins/steelseries/meson.build +++ b/plugins/steelseries/meson.build @@ -16,6 +16,9 @@ shared_module('fu_plugin_steelseries', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/superio/meson.build b/plugins/superio/meson.build index 57edaf93c..fb27ac504 100644 --- a/plugins/superio/meson.build +++ b/plugins/superio/meson.build @@ -16,6 +16,9 @@ shared_module('fu_plugin_superio', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/synapticsmst/meson.build b/plugins/synapticsmst/meson.build index 3a93115b2..197620b77 100644 --- a/plugins/synapticsmst/meson.build +++ b/plugins/synapticsmst/meson.build @@ -18,8 +18,11 @@ shared_module('fu_plugin_synapticsmst', install : true, install_dir: plugin_dir, c_args : [ - cargs, - ], + cargs, + ], + link_with : [ + libfwupdprivate, + ], dependencies : [ plugin_deps, ], @@ -47,7 +50,6 @@ if get_option('tests') valgrind, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : [ diff --git a/plugins/test/meson.build b/plugins/test/meson.build index 7f07a596c..2dfdd91e9 100644 --- a/plugins/test/meson.build +++ b/plugins/test/meson.build @@ -16,6 +16,9 @@ shared_module('fu_plugin_test', ], install : install_dummy, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/thunderbolt-power/meson.build b/plugins/thunderbolt-power/meson.build index 59257c6ed..1df672074 100644 --- a/plugins/thunderbolt-power/meson.build +++ b/plugins/thunderbolt-power/meson.build @@ -11,6 +11,9 @@ fu_plugin_thunderbolt_power = shared_module('fu_plugin_thunderbolt_power', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/thunderbolt/meson.build b/plugins/thunderbolt/meson.build index 17e81b73e..ce7c76203 100644 --- a/plugins/thunderbolt/meson.build +++ b/plugins/thunderbolt/meson.build @@ -12,6 +12,9 @@ fu_plugin_thunderbolt = shared_module('fu_plugin_thunderbolt', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -33,7 +36,6 @@ executable('tbtfwucli', c_args : cargs, link_with : [ fu_plugin_thunderbolt, - fwupd, libfwupdprivate, ], dependencies : [ @@ -62,7 +64,6 @@ if get_option('tests') and umockdev.found() and gio.version().version_compare('> umockdev, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff --git a/plugins/udev/meson.build b/plugins/udev/meson.build index cdadc08d2..33eb149ca 100644 --- a/plugins/udev/meson.build +++ b/plugins/udev/meson.build @@ -12,6 +12,9 @@ shared_module('fu_plugin_udev', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -33,7 +36,6 @@ executable( plugin_deps, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs, @@ -59,7 +61,6 @@ if get_option('tests') plugin_deps, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index 575f6c64e..09ebdf82d 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -26,6 +26,9 @@ shared_module('fu_plugin_uefi', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -62,7 +65,6 @@ executable( efiboot, ], link_with : [ - fwupd, libfwupdprivate, ], install : true, @@ -101,7 +103,6 @@ if get_option('tests') efiboot, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff --git a/plugins/unifying/meson.build b/plugins/unifying/meson.build index 011fd0187..f3ab13008 100644 --- a/plugins/unifying/meson.build +++ b/plugins/unifying/meson.build @@ -26,6 +26,9 @@ shared_module('fu_plugin_unifying', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -47,7 +50,7 @@ if get_option('tests') plugin_deps, ], link_with : [ - fwupd, + libfwupdprivate, ], c_args : cargs, ) diff --git a/plugins/upower/meson.build b/plugins/upower/meson.build index 9d027744b..62c7dfc54 100644 --- a/plugins/upower/meson.build +++ b/plugins/upower/meson.build @@ -11,6 +11,9 @@ shared_module('fu_plugin_upower', ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff --git a/plugins/wacom-usb/meson.build b/plugins/wacom-usb/meson.build index f7f74648d..44374232c 100644 --- a/plugins/wacom-usb/meson.build +++ b/plugins/wacom-usb/meson.build @@ -27,6 +27,7 @@ shared_module('fu_plugin_wacom_usb', plugin_deps, ], link_with : [ + libfwupdprivate, dfu, ], ) @@ -57,7 +58,6 @@ if get_option('tests') ], link_with : [ dfu, - fwupd, libfwupdprivate, ], c_args : cargs diff --git a/src/meson.build b/src/meson.build index 427801ee1..99e16a4d0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -59,6 +59,9 @@ libfwupdprivate = static_library( valgrind, uuid, ], + link_with : [ + fwupd, + ], c_args : [ '-DFU_OFFLINE_DESTDIR=""', ], From 8be03791c7b552ae4b0ccde530ab15266e2df01f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 26 Dec 2018 11:38:12 +0000 Subject: [PATCH 148/254] Log an error if started with an incompatible locale Test with `LC_ALL=de_DE.UTF-8 ./src/fwupd` --- src/fu-main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fu-main.c b/src/fu-main.c index edf9567b9..e50cacb2d 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1255,6 +1255,7 @@ main (int argc, char *argv[]) g_autoptr(FuMainPrivate) priv = NULL; g_autoptr(GError) error = NULL; g_autoptr(GOptionContext) context = NULL; + g_autofree gchar *version_tmp = NULL; setlocale (LC_ALL, ""); @@ -1262,6 +1263,11 @@ main (int argc, char *argv[]) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); + /* test we're in a C-ish locale */ + version_tmp = g_strdup_printf ("%.2f", 1.23f); + if (g_strcmp0 (version_tmp, "1.23") != 0) + g_printerr ("Started with an incompatible locale!\n"); + /* TRANSLATORS: program name */ g_set_application_name (_("Firmware Update Daemon")); context = g_option_context_new (NULL); From c2b4b56bd357591ce7b8ad58604891b52076f49f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 30 Dec 2018 15:19:01 +0000 Subject: [PATCH 149/254] Release fwupd 1.2.2 --- data/org.freedesktop.fwupd.metainfo.xml | 25 +++ po/ast.po | 13 +- po/ca.po | 49 +++-- po/cs.po | 16 +- po/de.po | 18 +- po/en_GB.po | 16 +- po/fi.po | 10 +- po/fr.po | 4 +- po/fur.po | 13 +- po/he.po | 4 +- po/hi.po | 4 +- po/hr.po | 16 +- po/hu.po | 265 ++++++++++++++++++++++-- po/id.po | 16 +- po/it.po | 51 +++-- po/ko.po | 16 +- po/nl.po | 4 +- po/oc.po | 4 +- po/pl.po | 59 ++++-- po/pt_BR.po | 110 ++++++++-- po/ru.po | 16 +- po/sk.po | 4 +- po/sr.po | 16 +- po/sv.po | 16 +- po/tr.po | 4 +- po/uk.po | 59 ++++-- po/zh_CN.po | 16 +- po/zh_TW.po | 16 +- 28 files changed, 569 insertions(+), 291 deletions(-) diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index ec990b185..452a24de9 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -31,6 +31,31 @@ moderate + + +

        This release adds the following features:

        +
          +
        • Add support for devices that support fastboot
        • +
        • Add more standard USB identifier GUIDs
        • +
        • Add new API to get the release protocol from the metadata
        • +
        • Add the PCR0 value as the device checksum for system firmware
        • +
        • Include the device firmware checksum and update protocol in the report
        • +
        +

        This release fixes the following bugs:

        +
          +
        • Add Dell TB18DC to the supported devices list
        • +
        • Allow replacing the last byte in the image when using 'dfu-tool replace-data'
        • +
        • Append the UEFI capsule header in userspace rather than in the loader
        • +
        • Check the device checksum as well as the content checksum during verify
        • +
        • Correctly parse format the version numbers correctly using old metadata
        • +
        • Fix a crash if AMT returns an empty response
        • +
        • Fix a regression when doing GetReleases on unsupported hardware
        • +
        • Fix the 8bitdo version number if the daemon locale is not C.UTF-8
        • +
        • Remove the Wacom DTH generation hardware from the whitelist
        • +
        • Sanitize the version if the version format has been specified
        • +
        +
        +

        This release adds the following features:

        diff --git a/po/ast.po b/po/ast.po index 772e32680..d9e6b2f35 100644 --- a/po/ast.po +++ b/po/ast.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Asturian (http://www.transifex.com/freedesktop/fwupd/language/ast/)\n" "MIME-Version: 1.0\n" @@ -78,15 +78,6 @@ msgstr "Estáu" msgid "Status" msgstr "Estáu" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Esti proyeutu tien l'oxetivu d'anovar automáticamente'l firmware en Linux d'un mou seguru y fiable. Pues usar un xestor de software GUI como Gnome Software pa ver y aplicar los anovamientos, la ferramienta en llinia de comandos o la interfaz D-Bus direutamente." - #. TRANSLATORS: transfer size in bytes msgid "Transfer Size" msgstr "Tamañu de tresferencia" - -msgid "Update device firmware on Linux" -msgstr "Anueva'l firmware de preseos en Linux" - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/ca.po b/po/ca.po index a2af6138b..ce33c478b 100644 --- a/po/ca.po +++ b/po/ca.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 12:35+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-29 15:25+0000\n" "Last-Translator: Antoni Bella Pérez \n" "Language-Team: Catalan (http://www.transifex.com/freedesktop/fwupd/language/ca/)\n" "MIME-Version: 1.0\n" @@ -31,6 +31,34 @@ msgstr[1] "Manquen %.0f minuts" msgid "%s has firmware updates:" msgstr "%s té actualitzacions de microprogramari:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dia" +msgstr[1] "%u dies" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hora" +msgstr[1] "%u hores" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minut" +msgstr[1] "%u minuts" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u segon" +msgstr[1] "%u segons" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "S'ha afegit" @@ -821,9 +849,6 @@ msgstr "Objectiu" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "El LVFS és un servei gratuït que funciona com una entitat legal independent i no té cap vincle amb la $OS_RELEASE:NAME$. És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats. Tot el microprogramari només és proporcionat pel fabricant original dels equips." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "El procés del «fwupd» és un dimoni senzill, el qual permet que una sessió de programari actualitzi el microprogramari del dispositiu a la màquina local. Està dissenyat per a equips d'escriptori, però aquest projecte també és usable a telèfons, tauletes i servidors sense perifèrics." - #. TRANSLATORS: exactly one update needs this msgid "The update requires a reboot to complete." msgstr "L'actualització requereix un reinici per a completar-se." @@ -832,9 +857,6 @@ msgstr "L'actualització requereix un reinici per a completar-se." msgid "This program may only work correctly as root" msgstr "Aquest programa només pot funcionar correctament com a «root»" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Aquest projecte pretén fer que actualitzar automàticament el microprogramari a Linux, sigui segur i fiable. Com a IGU, podeu usar un gestor de programari com el Programari GNOME per a veure i aplicar les actualitzacions, directament l'eina de la línia d'ordres o la interfície de D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Aquest remot conté el microprogramari que no està embargat, però encara l'ha provat el proveïdor del maquinari. Haureu d'assegurar-vos que teniu una manera de baixar manualment el microprogramari si l'actualització del microprogramari no funciona." @@ -881,6 +903,11 @@ msgstr "Suma de verificació de l'actualització" msgid "Update Description" msgstr "Descripció de l'actualització" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Durada de l'actualització" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Ubicació de l'actualització" @@ -901,9 +928,6 @@ msgstr "Actualitza el resum" msgid "Update Version" msgstr "Versió de l'actualització" -msgid "Update device firmware on Linux" -msgstr "Actualitza el microprogramari del dispositiu a Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Que falli en actualitzar és un problema conegut, visiteu aquest URL per obtenir més informació:" @@ -986,6 +1010,3 @@ msgstr "S'està escrivint..." #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/cs.po b/po/cs.po index 5554e9aac..7a25ec226 100644 --- a/po/cs.po +++ b/po/cs.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Czech (http://www.transifex.com/freedesktop/fwupd/language/cs/)\n" "MIME-Version: 1.0\n" @@ -802,9 +802,6 @@ msgstr "Cíl" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Proces fwupd je jednoduchý démon, který umožňuje softwaru sezení aktualizovat firmware zařízení na vašem počítači. Je navržen pro stolní počítače, ale je možné jej používat i na telefonech, tabletech a serverech bez monitoru." - #. TRANSLATORS: exactly one update needs this msgid "The update requires a reboot to complete." msgstr "Pro dokončení aktualizace je potřeba provést restart." @@ -813,9 +810,6 @@ msgstr "Pro dokončení aktualizace je potřeba provést restart." msgid "This program may only work correctly as root" msgstr "Tento program může správně fungovat jen pod uživatelem root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Cílem tohoto projektu je, aby aktualizace firmwaru na Linuxu probíhala automaticky, bezpečně a spolehlivě. Pro zobrazení a nasazení aktualizací můžete použít správce softwaru s grafickým rozhraním, jako je třeba Software GNOME, nebo nástroj pro příkazovou řádku či přímo rozhraní D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Tento zdroj obsahuje firmware, který není zakázaný, ale zatím je u výrobce stále ve stádiu testování. Měli byste se ujistit, že znáte způsob, jak se vrátit k předchozí verzi firmwaru, kdyby došlo k selhání." @@ -882,9 +876,6 @@ msgstr "Souhrn aktualizace" msgid "Update Version" msgstr "Verze aktualizace" -msgid "Update device firmware on Linux" -msgstr "Aktualizace firmwaru zařízení na Linuxu" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "O selhání aktualizace se ví, více informací najdete na této adrese:" @@ -962,6 +953,3 @@ msgstr "Zapisuje se…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Váš distributor nemusí schválit některé aktualizace firmwaru kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/de.po b/po/de.po index 72e8cfdad..9841a1c86 100644 --- a/po/de.po +++ b/po/de.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-27 22:37+0000\n" -"Last-Translator: Ettore Atalan \n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" +"Last-Translator: Richard Hughes \n" "Language-Team: German (http://www.transifex.com/freedesktop/fwupd/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -744,9 +744,6 @@ msgstr "Ziel" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "Der LVFS ist ein kostenloser Dienst, der als unabhängige juristische Person arbeitet und keine Verbindung zu $OS_RELEASE:NAME$ hat. Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft. Die gesamte Firmware wird nur vom Originalhersteller zur Verfügung gestellt." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Der fwupd-Prozess ist ein einfaches Hintergrundprogramm, der es der Sitzungssoftware ermöglicht, die Geräte-Firmware auf Ihrem lokalen System zu aktualisieren. Es ist für Desktops konzipiert, aber dieses Projekt ist auch auf Telefonen, Tablets und Headless-Servern einsetzbar." - #. TRANSLATORS: exactly one update needs this msgid "The update requires a reboot to complete." msgstr "Ein Neustart ist erforderlich, um die Aktualisierung abzuschließen." @@ -755,9 +752,6 @@ msgstr "Ein Neustart ist erforderlich, um die Aktualisierung abzuschließen." msgid "This program may only work correctly as root" msgstr "Dieses Programm funktioniert möglicherweise nur als root korrekt" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Ziel dieses Projekts ist es, die Aktualisierung der Firmware unter Linux automatisch, sicher und zuverlässig zu machen. Zum Anzeigen und Anwenden von Aktualisierungen können Sie entweder eine GUI-Softwareverwaltung wie GNOME Software, das Befehlszeilenwerkzeug oder die D-Bus-Schnittstelle direkt verwenden." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Titel" @@ -813,9 +807,6 @@ msgstr "Aktualisierungszusammenfassung" msgid "Update Version" msgstr "Version aktualisieren" -msgid "Update device firmware on Linux" -msgstr "Geräte-Firmware unter Linux aktualisieren" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Der Aktualisierungsfehler ist ein bekanntes Problem, besuchen Sie diese URL für weitere Informationen:" @@ -898,6 +889,3 @@ msgstr "Schreiben …" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/en_GB.po b/po/en_GB.po index d6b2a2c5c..a29d59e3a 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/freedesktop/fwupd/language/en_GB/)\n" "MIME-Version: 1.0\n" @@ -610,12 +610,6 @@ msgstr "Summary" msgid "Target" msgstr "Target" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Title" @@ -671,9 +665,6 @@ msgstr "Update Summary" msgid "Update Version" msgstr "Update Version" -msgid "Update device firmware on Linux" -msgstr "Update device firmware on Linux" - #. TRANSLATORS: ask the user if we can update the metadata msgid "Update now?" msgstr "Update now?" @@ -731,6 +722,3 @@ msgstr "Write firmware from file into one partition" #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Writing…" - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/fi.po b/po/fi.po index 0e501ab0d..da403fca1 100644 --- a/po/fi.po +++ b/po/fi.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Finnish (http://www.transifex.com/freedesktop/fwupd/language/fi/)\n" "MIME-Version: 1.0\n" @@ -180,9 +180,6 @@ msgstr "Tyyppi" msgid "Unknown" msgstr "Tuntematon" -msgid "Update device firmware on Linux" -msgstr "Päivitä laitteiden firmware-laiteohjelmistoja Linuxilla" - #. TRANSLATORS: remote filename base msgid "Username" msgstr "Käyttäjätunnus" @@ -202,6 +199,3 @@ msgstr "Odotetaan…" #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Kirjoitetaan…" - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/fr.po b/po/fr.po index 2da1ac94a..5650849dd 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: French (http://www.transifex.com/freedesktop/fwupd/language/fr/)\n" "MIME-Version: 1.0\n" diff --git a/po/fur.po b/po/fur.po index d18122f44..cfff7927a 100644 --- a/po/fur.po +++ b/po/fur.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Friulian (http://www.transifex.com/freedesktop/fwupd/language/fur/)\n" "MIME-Version: 1.0\n" @@ -562,9 +562,6 @@ msgstr "Stât" msgid "Summary" msgstr "Sintesi" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Il procès fwupd al è un sempliç demoni par permeti al software de session di inzornâ i firmware dai dispositîfs su la machine locâl. Al è progjetât pai scritoris, ma chest progjet si pues doprâ ancje sui telefonins, tablet e sui servidôrs cence visôr." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Titul" @@ -616,9 +613,6 @@ msgstr "Inzorne sintesi" msgid "Update Version" msgstr "Inzorne version" -msgid "Update device firmware on Linux" -msgstr "Inzorne il firmware dal dispositîf su Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Il faliment dal inzornament al è un probleme cognossût, visite chest URL par vê plui informazions:" @@ -672,6 +666,3 @@ msgstr "Scrîf il firmware dal file intune partizion" #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Daûr a scrivi…" - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/he.po b/po/he.po index 58ed9a36a..8b2a58924 100644 --- a/po/he.po +++ b/po/he.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hebrew (http://www.transifex.com/freedesktop/fwupd/language/he/)\n" "MIME-Version: 1.0\n" diff --git a/po/hi.po b/po/hi.po index 4a990c8e1..abdad4ffd 100644 --- a/po/hi.po +++ b/po/hi.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Hindi (http://www.transifex.com/freedesktop/fwupd/language/hi/)\n" "MIME-Version: 1.0\n" diff --git a/po/hr.po b/po/hr.po index 7784f6240..7dc5b42ec 100644 --- a/po/hr.po +++ b/po/hr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Croatian (http://www.transifex.com/freedesktop/fwupd/language/hr/)\n" "MIME-Version: 1.0\n" @@ -638,12 +638,6 @@ msgstr "Sažetak" msgid "Target" msgstr "Odredište" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd je jednostavan pozadinski program koji omogućuje softveru sesije nadopunu frimvera uređaja na vašem lokalnom računalu. Dizajniran je za stolna računala, ali ovaj projekt se može koristiti i na mobilnim telefonima, tabletima i poslužiteljima." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Svrha ovog projekta je automatsko, sigurno i pouzdano nadopunjivanje frimvera na linuxu. Kako bi vidjeli i primijenili nadopune frimvera možete koristiti upravitelja softverom poput GNOME Softvera, alat naredbenog redka ili izravno D-Bus sučelje." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Naziv" @@ -699,9 +693,6 @@ msgstr "Sažetak nadopune" msgid "Update Version" msgstr "Inačica nadopune" -msgid "Update device firmware on Linux" -msgstr "Nadopunite frimvere uređaja na Linuxu" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Neuspješna nadopuna je poznat problem, posjetite ovaj URL za više informacija:" @@ -767,6 +758,3 @@ msgstr "Zapiši frimver iz datoteke u jednu particiju uređaja" #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Zapisivanje..." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/hu.po b/po/hu.po index 0acb31339..c2fd3858d 100644 --- a/po/hu.po +++ b/po/hu.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-12-16 19:43+0000\n" +"Last-Translator: Balázs Meskó \n" "Language-Team: Hungarian (http://www.transifex.com/freedesktop/fwupd/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,11 +21,46 @@ msgstr "" "Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f perc van hátra" +msgstr[1] "%.0f perc van hátra" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s firmware frissítésekkel rendelkezik:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u nap" +msgstr[1] "%u nap" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u óra" +msgstr[1] "%u óra" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u perc" +msgstr[1] "%u perc" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u másodperc" +msgstr[1] "%u másodperc" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Hozzáadva" @@ -34,6 +69,10 @@ msgstr "Hozzáadva" msgid "Age" msgstr "Kor" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Beleegyezik és engedélyezi a távoli tárolót?" + #. TRANSLATORS: this is a command alias, e.g. 'get-devices' #, c-format msgid "Alias to %s" @@ -59,10 +98,18 @@ msgstr "Igen az összes kérdésre" msgid "Apply a binary patch" msgstr "Bináris folt alkalmazása" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Firmware-frissítések alkalmazása" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "DFU-képes eszköz visszacsatolása a futtatókörnyezethez" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Csatlakoztatás a firmware módhoz" + #. TRANSLATORS: device attributes, i.e. things that #. * the device can do msgid "Attributes" @@ -185,6 +232,10 @@ msgstr "Leírás" msgid "Detach currently attached DFU capable device" msgstr "Jelenleg csatlakoztatott DFU-képes eszközök leválasztása" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Leválasztás a indítóbetöltő módhoz" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Eszköz hozzáadva:" @@ -205,6 +256,17 @@ msgstr "Eszközök, melyek sikeresen frissítve lettek:" msgid "Devices that were not updated correctly:" msgstr "Eszközök, melyek nem lettek helyesen frissítve:" +msgid "Disabled fwupdate debugging" +msgstr "Fwupdate hibakeresés letiltva" + +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "Letiltja az adott távoli tárolót" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Verzió megjelenítése" + #. TRANSLATORS: command line option msgid "Do not check for old metadata" msgstr "Ne ellenőrizze a régi metaadatokat" @@ -217,6 +279,10 @@ msgstr "Ne ellenőrizze az újraindítást a frissítés után" msgid "Do not check for unreported history" msgstr "Ne ellenőrizze a nem jelentett előzményeket" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Ne írjon az előzmények adatbázisába" + msgid "Done!" msgstr "Kész!" @@ -231,6 +297,11 @@ msgstr "A firmware visszafejlesztése az eszközön" msgid "Downgrading %s from %s to %s... " msgstr "%s visszafejlesztése: %s -> %s…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "%s visszaállítása…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Letöltés…" @@ -247,10 +318,36 @@ msgstr "Részletek kiírása egy firmware fájlról" msgid "Dump information about a binary patch to the screen" msgstr "Információk kiírása a képernyőre a bináris foltról" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "A megadott ESP érvénytelen" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Firmware frissítési támogatás engedélyezése a támogatott rendszereken" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Engedélyezi ezt a távoli tárolót?" + #. TRANSLATORS: if the remote is enabled msgid "Enabled" msgstr "Engedélyezve" +msgid "Enabled fwupdate debugging" +msgstr "Fwupdate hibakeresés engedélyezve" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Engedélyezi az adott távoli tárolót" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Csak a saját felelősségére engedélyezze ezt a funkciót, amely azt jelenti, hogy az eredeti termék gyártójával kell kapcsolatba lépnie, ha problémát okoz a frissítés. Csak a frissítési folyamattal kapcsolatos problémákat jelentse itt be: $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "A saját felelősségére engedélyezze ezt a távoli tárolót." + #. TRANSLATORS: command description msgid "Encrypt firmware data" msgstr "Firmware adatok titkosítása" @@ -271,6 +368,10 @@ msgstr "Kilépés egy kis késleltetés után" msgid "Exit after the engine has loaded" msgstr "Kilépés a motor betöltődése után" +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "A letöltés kiszolgálókorlát miatt meghiúsult" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "A trükkök betöltése sikertelen" @@ -326,6 +427,15 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." msgstr[1] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." +msgid "Firmware updates are not supported on this machine." +msgstr "A firmware frissítések nem támogatottak ezen a gépen." + +msgid "Firmware updates are supported on this machine." +msgstr "A firmware frissítések támogatottak ezen a gépen." + +msgid "Force the action ignoring all warnings" +msgstr "A művelet erőltetése, az összes figyelmeztetés mellőzése" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Megtalálva" @@ -333,10 +443,18 @@ msgstr "Megtalálva" msgid "GUID" msgstr "GUID" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Az összes eszköz lekérdezése a rendszer topológiájának megfelelően" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Minden eszköz lekérése, amelyek támogatják a firmware frissítéseket" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Az összes rendszeren regisztrált és engedélyezett bővítmény lekérdezése" + #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Részleteket kér le egy firmware fájlról" @@ -369,6 +487,10 @@ msgstr "Azonosító" msgid "Idle…" msgstr "Üresjárat…" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Firmware blob telepítése egy eszközre" + #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Egy firmware fájl telepítése ezen a hardveren" @@ -392,21 +514,50 @@ msgstr "Nem aláírt eszköz firmware telepítése" msgid "Install unsigned system firmware" msgstr "Nem aláírt rendszer firmware telepítése" +#. show message in progressbar +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing %s" +msgstr "%s telepítése" + #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Firmware frissítés telepítése…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "%s telepítése…" + msgid "Keyring" msgstr "Kulcstartó" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Kevesebb mint egy perc van hátra" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux gyártói firmware szolgáltatás (stabil firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux gyártói firmware szolgáltatás (teszt firmware)" + #. TRANSLATORS: command description msgid "List currently attached DFU capable devices" msgstr "Jelenleg csatlakoztatott DFU-képes eszközök felsorolása" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "A támogatott firmware-frissítések listázása" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Betöltés…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Egyes bővítmények kézi fehérlistára tétele" + #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Több firmware fájl egyesítése" @@ -419,6 +570,10 @@ msgstr "Metaadat URI" msgid "Metadata URI Signature" msgstr "Metaadat URI aláírása" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "A metaadatok nem szerezhetőek be a Linux gyártói firmware szolgáltatásból." + msgid "Mode" msgstr "Mód" @@ -439,11 +594,22 @@ msgstr "A démon eseményeinek figyelése" msgid "Name" msgstr "Név" +msgid "No action specified!" +msgstr "Nincs művelet megadva!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Nem észlelhető firmware frissítési képességgel rendelkező hardver" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nem található bővítmény" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Jelenleg nincsenek engedélyezett távoli tárolók, így nem érhetőek el metaadatok." + msgid "OK" msgstr "OK" @@ -451,6 +617,10 @@ msgstr "OK" msgid "Override plugin warning" msgstr "Bővítmény figyelmeztetés felülbírálása" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Az alapértelmezett ESP útvonal felülbírálása" + #. TRANSLATORS: remote filename base msgid "Password" msgstr "Jelszó" @@ -466,6 +636,12 @@ msgstr "Hozzáférés megtagadva" msgid "Please enter a number from 0 to %u: " msgstr "Adjon meg egy számot 0 és %u között:" +msgid "Print the version number" +msgstr "A verziószám kiírása." + +msgid "Print verbose debug statements" +msgstr "Részletes hibakeresési utasítások kiírása" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioritás" @@ -477,6 +653,10 @@ msgstr "Folytatja a feltöltést?" msgid "Protocol" msgstr "Protokoll" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Firmware frissítési támogatás lekérdezése" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -547,7 +727,7 @@ msgstr "Eszköz újraindítása…" #. TRANSLATORS: command description msgid "Return all the hardware IDs for the machine" -msgstr "A géphez tartoó összes hardverazonosító visszaadása" +msgstr "A géphez tartozó összes hardverazonosító visszaadása" msgid "Runtime" msgstr "Futtatókörnyezet" @@ -584,6 +764,10 @@ msgstr "Termékazonosító beállítása a firmware fájlon" msgid "Set release version on firmware file" msgstr "Kiadási verzió beállítása a firmware fájlon" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "A hibakeresési jelző beállítása frissítéskor" + #. TRANSLATORS: command description msgid "Set the firmware size for the target" msgstr "A firmware méretének beállítása a célhoz" @@ -604,6 +788,10 @@ msgstr "Firmware frissítése előzmények megosztása a fejlesztőkkel" msgid "Show client and daemon versions" msgstr "Ügyfél és démon verziók megjelenítése" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "A démon részletes információinak megjelenítése" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Hibakeresési információk megjelenítése minden fájlnál" @@ -612,6 +800,10 @@ msgstr "Hibakeresési információk megjelenítése minden fájlnál" msgid "Show debugging options" msgstr "Hibakeresési beállítások megjelenítése" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Eszközök, melyek nem frissíthetőek" + #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "További hibakeresési információk megjelenítése" @@ -624,6 +816,20 @@ msgstr "Firmware frissítési előzmények megtekintése" msgid "Show plugin verbose information" msgstr "Bővítmény bőbeszédű információinak megjelenítése" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "A legutóbb megpróbált frissítés hibakeresési naplójának megjelenítése" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "A firmware frissítési állapot információinak megjelenítése" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Adja meg a DFU eszköz gyártó-/termékazonosítóját" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Adja meg az USB átvitelek bájtjainak számát" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Állapot" @@ -641,11 +847,20 @@ msgstr "Összegzés" msgid "Target" msgstr "Cél" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "A fwupd folyamat egy egyszerű démon, amely lehetővé teszi más szoftvereknek a számítógép eszközeinek firmware-jének frissítését. Asztali számítógépekre lett tervezve, de használható telefonokon, táblagépeken és képernyő nélküli kiszolgálókon is. " +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "Az LVFS egy ingyenes szolgáltatás, amely független jogi entitásként működik, és nincs kapcsolata a $OS_RELEASE:NAME$ operációs rendszerrel. A disztribúció szállítója nem biztos, hogy ellenőrízte kompatibilitási szempontból a firmware frissítést. Mindent firmware-t csak az eredeti termék gyártója biztosít." -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "A projekt célja a firmwarek frissítését automatikussá, biztonságossá és megbízhatóvá tétele Linuxon. Használhat grafikus szoftverkezelőket, mint a GNOME Szoftverek a frissítések megtekintéséhez és alkalmazásához, használhatja a parancssoros eszközt, vagy közvetlenül a D-Bus interfészt." +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "A frissítés befejezéséhez újraindítás szükséges." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Ez a program jelenleg lehet, hogy csak rendszergazdaként működik" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Ez a távoli tároló olyan firmware-t tartalmaz, amelyre nem vonatkozik embargó, de még teszteli a harvergyártó. Érdemes biztosítani a firmware kézi visszaállításáról, ha a firmware frissítése meghiúsul." #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" @@ -659,6 +874,10 @@ msgstr "Átviteli méret" msgid "Type" msgstr "Típus" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI firmware segédprogram" + #. TRANSLATORS: section header for firmware URI msgid "URI" msgstr "URI" @@ -674,6 +893,10 @@ msgstr "Eszköz feloldása hozzáférés engedélyezéséhez" msgid "Unlocks the device for firmware access" msgstr "Eszköz feloldása a firmware eléréséhez" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "A hibakeresési jelző kikapcsolása frissítéskor" + #. TRANSLATORS: section header for firmware checksum msgid "Update Checksum" msgstr "Frissítés ellenőrzőösszege" @@ -682,6 +905,11 @@ msgstr "Frissítés ellenőrzőösszege" msgid "Update Description" msgstr "Frissítés leírása" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Frissítés hossza" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Frissítés helye" @@ -702,9 +930,6 @@ msgstr "Frissítés összegzése" msgid "Update Version" msgstr "Frissítés verziója" -msgid "Update device firmware on Linux" -msgstr "Eszköz firmware frissítése Linuxon" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "A feltöltési hiba ismert probléma, további információkért látogassa meg ezt az URL-t:" @@ -731,6 +956,11 @@ msgstr "Minden firmware-t az elérhető legfrissebb verziókra frissít" msgid "Updating %s from %s to %s... " msgstr "%s frissítése: %s -> %s…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "%s frissítése…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Feltöltési üzenet:" @@ -739,6 +969,10 @@ msgstr "Feltöltési üzenet:" msgid "Upload report now?" msgstr "Feltölti most a jelentést?" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "A firmware jelentések segítenek a hardvergyártóknak, hogy gyorsan azonosítsák a hibás és sikeres frissítéseket valós eszközökön." + #. TRANSLATORS: remote filename base msgid "Username" msgstr "Felhasználónév" @@ -759,6 +993,10 @@ msgstr "Várakozás…" msgid "Watch DFU devices being hotplugged" msgstr "DFU-eszközök menet közbeni csatlakoztatásának figyelése" +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Hardverváltozások figyelése" + #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Firmware írása fájlból egy eszközre" @@ -771,5 +1009,6 @@ msgstr "Firmware írása fájlból egy partícióra" msgid "Writing…" msgstr "Írás…" -msgid "fwupd" -msgstr "fwupd" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "A disztribúció szállítója nem biztos, hogy ellenőrízte a firmware frissítés kompatibilitását a rendszerével és a kapcsolódó eszközeivel." diff --git a/po/id.po b/po/id.po index 3dc783e54..dff70f4fb 100644 --- a/po/id.po +++ b/po/id.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Indonesian (http://www.transifex.com/freedesktop/fwupd/language/id/)\n" "MIME-Version: 1.0\n" @@ -628,12 +628,6 @@ msgstr "Ringkasan" msgid "Target" msgstr "Target" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Proses fwupd adalah sebuah daemon sederhana yang memungkinkan perangkat lunak sesi memperbarui firmware peranti pada mesin lokal Anda. Ini dirancang untuk desktop, tapi proyek ini juga dapat dipakai pada telepon, tablet, dan server headless." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Proyek ini bertujuan membuat pemutakhiran firmware pada Linux otomatis, aman, dan handal. Anda dapat memakai manajer perangkat lunak GUI seperti GNOME Perangkat Lunak untuk melihat dan menerapkan pembaruan, perkakas perintah baris, atau antar muka D-Bus secara langsung." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Judul" @@ -689,9 +683,6 @@ msgstr "Ringkasan Pembaruan" msgid "Update Version" msgstr "Mutakhirkan Versi" -msgid "Update device firmware on Linux" -msgstr "Perbarui firmware peranti pada Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Kegagalan pembaruan adalah masalah yang telah diketahui, kunjungi URL ini untuk informasi lebih lanjut:" @@ -757,6 +748,3 @@ msgstr "Tulis firmware dari berkas ke dalam suatu partisi" #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Menulis..." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/it.po b/po/it.po index 944c46288..3824307ff 100644 --- a/po/it.po +++ b/po/it.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 13:29+0000\n" -"Last-Translator: Milo Casagrande \n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" +"Last-Translator: Richard Hughes \n" "Language-Team: Italian (http://www.transifex.com/freedesktop/fwupd/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,6 +31,34 @@ msgstr[1] "Mancano %.0f minuti" msgid "%s has firmware updates:" msgstr "%s ha degli aggiornamenti del firmware:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u giorno" +msgstr[1] "%u giorni" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u ora" +msgstr[1] "%u ore" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuto" +msgstr[1] "%u minuti" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u secondo" +msgstr[1] "%u secondi" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Aggiunto" @@ -821,9 +849,6 @@ msgstr "Obiettivo" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente e non ha alcun legame con $OS_RELEASE:NAME$. Il distributore potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o con i propri dispositivi collegati. Il firmware viene fornito solamente dall'OEM." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Il processo fwupd è un demone che consente di aggiornare il firmware di un dispositivo sul proprio computer. È progettato per un ambiente desktop, ma è possibile utilizzarlo anche su telefonini, tablet e server." - #. TRANSLATORS: exactly one update needs this msgid "The update requires a reboot to complete." msgstr "Per essere completato, l'aggiornamento richiede un riavvio." @@ -832,9 +857,6 @@ msgstr "Per essere completato, l'aggiornamento richiede un riavvio." msgid "This program may only work correctly as root" msgstr "Questo programma può funzionare correttamente solo come utente root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Questo progetto vuole rendere l'aggiornamento di firmware su Linux un processo automatico, sicuro e affidabile. È possibile usare uno strumento grafico come GNOME Software per visualizzare e applicare gli aggiornamenti, oppure lo strumento a riga di comando o l'interfaccia D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Questo remoto contiene firmware che non è bloccato, ma è ancora in fase di verifica dal produttore hardware. Assicurarsi di poter ripristinare, manualmente o con altre procedure, il vecchio firmware nel caso in cui l'aggiornamento non riuscisse." @@ -881,6 +903,11 @@ msgstr "Codice di controllo aggiornamento" msgid "Update Description" msgstr "Descrizione aggiornamento" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Durata aggiornamento" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Posizione aggiornamento" @@ -901,9 +928,6 @@ msgstr "Riepilogo aggiornameto" msgid "Update Version" msgstr "Versione aggiornamento" -msgid "Update device firmware on Linux" -msgstr "Aggiorna firmware dispositivi su Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Questo è un problema noto, consultare il seguente URL per maggiori informazioni:" @@ -986,6 +1010,3 @@ msgstr "Scrittura…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "La propria distribuzione potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o col dispositivo collegato." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/ko.po b/po/ko.po index 62cf045d2..61e1c78c6 100644 --- a/po/ko.po +++ b/po/ko.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Korean (http://www.transifex.com/freedesktop/fwupd/language/ko/)\n" "MIME-Version: 1.0\n" @@ -770,16 +770,10 @@ msgstr "대상" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS는 $OS_RELEASE:NAME$와(과) 별개로 운영되는 독립된 법적 단체에서 운영하는 무료 서비스입니다. 배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결된 장치간의 호환성을 검증한다는 보장이 없습니다. 모든 펌웨어는 원 장치 제조사(OEM)에서 직접 제공합니다." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 프로세스는 로컬 머신의 장치 펌웨어를 세션 프로그램에서 업데이트할 수 있게 하는 간단한 데몬입니다. 데스크톱용으로 설계했지만, 전화기, 태블릿, 헤드리스 서버에서도 사용할 수 있습니다." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "이 프로그램은 루트 권한으로만 올바르게 작동할 수도 있습니다" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "이 프로젝트에서는 리눅스에서 자동으로 안전하고 믿을 수 있게 펌웨어를 업데이트할 수 있게 하려고 합니다. 그놈 소프트웨어와 같은 GUI 도구로 업데이트를 보고 적용하거나, 명령행 도구 및 D-Bus 인터페이스를 직접 사용할 수 있습니다." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "이 원격 저장소에서는 하드웨어 제조사에서 검증 단계를 진행 중인 펌웨어를 배포합니다. 펌웨어 업데이트 도중 및 이후 문제가 발생했을 때 수동으로 펌웨어를 다운그레이드할 방법을 찾아 두는 것을 추천합니다." @@ -846,9 +840,6 @@ msgstr "업데이트 요약" msgid "Update Version" msgstr "업데이트 버전" -msgid "Update device firmware on Linux" -msgstr "리눅스에서 장치 펌웨어를 업데이트합니다" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "알 수 없는 이유로 업데이트가 실패했습니다. 더 많은 정보를 보려면 다음 URL을 참조가힙시오:" @@ -926,6 +917,3 @@ msgstr "쓰는 중…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결된 장치간의 호환성을 검증한다는 보장이 없습니다." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/nl.po b/po/nl.po index 6644a59ad..bd18d686c 100644 --- a/po/nl.po +++ b/po/nl.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Dutch (http://www.transifex.com/freedesktop/fwupd/language/nl/)\n" "MIME-Version: 1.0\n" diff --git a/po/oc.po b/po/oc.po index eb3b1a9b0..de4a1215a 100644 --- a/po/oc.po +++ b/po/oc.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Occitan (post 1500) (http://www.transifex.com/freedesktop/fwupd/language/oc/)\n" "MIME-Version: 1.0\n" diff --git a/po/pl.po b/po/pl.po index 4686792b4..fb81b1c93 100644 --- a/po/pl.po +++ b/po/pl.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 15:22+0000\n" -"Last-Translator: Piotr Drąg \n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" +"Last-Translator: Richard Hughes \n" "Language-Team: Polish (http://www.transifex.com/freedesktop/fwupd/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -32,6 +32,42 @@ msgstr[3] "Pozostało %.0f minut" msgid "%s has firmware updates:" msgstr "Dostępne są aktualizacje oprogramowania sprzętowego dla urządzenia %s:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dzień" +msgstr[1] "%u dni" +msgstr[2] "%u dni" +msgstr[3] "%u dni" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u godzina" +msgstr[1] "%u godziny" +msgstr[2] "%u godzin" +msgstr[3] "%u godzin" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuta" +msgstr[1] "%u minuty" +msgstr[2] "%u minut" +msgstr[3] "%u minut" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekunda" +msgstr[1] "%u sekundy" +msgstr[2] "%u sekund" +msgstr[3] "%u sekund" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Dodano" @@ -824,9 +860,6 @@ msgstr "Cel" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS to wolny serwis działający jako niezależny podmiot prawny niemający związków z systemem $OS_RELEASE:NAME$. Dystrybutor używanego systemu mógł nie zweryfikować żadnych aktualizacji oprogramowania sprzętowego pod kątem zgodności z używanym komputerem lub podłączonymi urządzeniami. Każde oprogramowanie sprzętowe jest dostarczane wyłącznie przez oryginalnego producenta sprzętu." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Proces fwupd to prosta usługa umożliwiająca aktualizowanie oprogramowania sprzętowego komputera w sesji użytkownika. Jest zaprojektowana dla komputerów osobistych, ale można jej używać także na telefonach, tabletach i serwerach bez monitorów." - #. TRANSLATORS: exactly one update needs this msgid "The update requires a reboot to complete." msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." @@ -835,9 +868,6 @@ msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." msgid "This program may only work correctly as root" msgstr "Ten program może działać poprawnie tylko jako root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Celem projektu jest automatyczne, bezpieczne i pewne aktualizowanie oprogramowania sprzętowego w systemie Linux. Można używać graficznego menedżera oprogramowania, takiego jak Menedżer oprogramowania GNOME do wyświetlania i zastosowywania aktualizacji, narzędzia wiersza poleceń lub bezpośrednio interfejsu D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "To repozytorium zawiera oprogramowanie sprzętowe nieobjęte embargo, ale nadal testowane przez dostawcę sprzętu. Należy upewnić się, że istnieje możliwość ręcznego zainstalowania poprzedniej wersji oprogramowania sprzętowego w razie niepowodzenia aktualizacji." @@ -884,6 +914,11 @@ msgstr "Suma kontrolna aktualizacji" msgid "Update Description" msgstr "Opis aktualizacji" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Czas trwania aktualizacji" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Położenie aktualizacji" @@ -904,9 +939,6 @@ msgstr "Podsumowanie aktualizacji" msgid "Update Version" msgstr "Wersja aktualizacji" -msgid "Update device firmware on Linux" -msgstr "Aktualizowanie oprogramowania sprzętowego w systemie Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Niepowodzenie aktualizacji to znany problem, pod tym adresem dostępnych jest więcej informacji:" @@ -989,6 +1021,3 @@ msgstr "Zapisywanie…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Używana dystrybucja mogła nie sprawdzić zgodności aktualizacji oprogramowania sprzętowego z komputerem i podłączonymi urządzeniami." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/pt_BR.po b/po/pt_BR.po index 78c804b1e..ffa3dc9f3 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -6,15 +6,15 @@ # Derek W. Stavis , 2015 # Derek W. Stavis , 2016 # Derek W. Stavis , 2015-2016 -# Rafael Fontenelle , 2017 +# Rafael Fontenelle , 2017-2018 # Rafael Fontenelle , 2015-2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-12-05 22:10+0000\n" +"Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/freedesktop/fwupd/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -22,11 +22,46 @@ msgstr "" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuto restante" +msgstr[1] "%.0f minutos restantes" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s tem atualizações de firmware:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dia" +msgstr[1] "%u dias" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hora" +msgstr[1] "%u horas" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuto" +msgstr[1] "%u minutos" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u segundo" +msgstr[1] "%u segundos" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Adicionado" @@ -46,7 +81,7 @@ msgstr "Atalho para %s" #. TRANSLATORS: command line option msgid "Allow downgrading firmware versions" -msgstr "Permite reverter versões de firmware" +msgstr "Permite fazer downgrade de versões de firmware" #. TRANSLATORS: command line option msgid "Allow re-installing existing firmware versions" @@ -87,11 +122,11 @@ msgstr "Autenticando…" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on a removable device" -msgstr "É requerida autenticação para voltar a versão do firmware em um dispositivo removível" +msgstr "É requerida autenticação para fazer downgrade da versão do firmware em um dispositivo removível" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "É requerida autenticação para voltar a versão do firmware nesta máquina" +msgstr "É requerida autenticação para fazer downgrade da versão do firmware nesta máquina" #. TRANSLATORS: this is the PolicyKit modal dialog msgid "Authentication is required to modify a configured remote used for firmware updates" @@ -254,14 +289,19 @@ msgstr "Feito!" #. TRANSLATORS: command description msgid "Downgrades the firmware on a device" -msgstr "Retrocede a versão do firmware em um dispositivo" +msgstr "Faz downgrade da versão do firmware em um dispositivo" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" #, c-format msgid "Downgrading %s from %s to %s... " -msgstr "Revertendo %s de %s para %s… " +msgstr "Fazendo downgrade de %s de %s para %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Fazendo downgrade %s…" #. TRANSLATORS: downloading from a remote server msgid "Downloading…" @@ -394,6 +434,9 @@ msgstr "Não há suporte a atualizações de firmware nessa máquina." msgid "Firmware updates are supported on this machine." msgstr "Há suporte a atualizações de firmware nesta máquina." +msgid "Force the action ignoring all warnings" +msgstr "Força a ação ignorando todos avisos" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Encontrado" @@ -482,9 +525,18 @@ msgstr "Instalando %s" msgid "Installing firmware update…" msgstr "Instalando atualização de firmware…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Instalando em %s…" + msgid "Keyring" msgstr "Chaveiro" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Menos que um minuto restante" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux Vendor Firmware Service (firmware estável)" @@ -585,6 +637,12 @@ msgstr "Permissão negada" msgid "Please enter a number from 0 to %u: " msgstr "Por favor, insira um número de 0 a %u: " +msgid "Print the version number" +msgstr "Imprime o número de versão" + +msgid "Print verbose debug statements" +msgstr "Imprime instruções de depuração verbosas" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioridade" @@ -731,6 +789,10 @@ msgstr "Compartilha histórico de firmware com os desenvolvedores" msgid "Show client and daemon versions" msgstr "Mostra as versões do cliente e do daemon" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Mostra informações verbosas de daemon" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Mostrar informações de depuração para todos os arquivos" @@ -763,6 +825,12 @@ msgstr "Mostra o registro log de depuração da tentativa mais recente de atuali msgid "Show the information of firmware update status" msgstr "Mostra as informações do status de atualização de firmware" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifica ID(s) de Fornecedor/Produto de dispositivo DFU" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifica o número de bytes por transferência USB" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Estado" @@ -784,16 +852,14 @@ msgstr "Alvo" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "O LVFS é um serviço livre que opera como uma entidade legal independente e tem nenhuma conexão com $OS_RELEASE:NAME$. Seu distribuidor pode não ter verificado alguma das atualizações de firmware por compatibilidade com seu sistema ou dispositivos conectados. Todos os firmwares são fornecidos apenas pelo fabricante do equipamento original." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "O fwupd processa é um daemon simples para permitir que software sessão atualizem firmware de dispositivo em seu computador local. É projetado para computadores de mesa, mas esse projeto também é usável em telefones, tablets e em servidores “headless” (sem monitor, teclado e mouse)." +#. TRANSLATORS: exactly one update needs this +msgid "The update requires a reboot to complete." +msgstr "A atualização requer uma reinicialização para completar." #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Esse programa só pode funcionar corretamente como root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Esse projeto visa tornar a atualização de firmware no Linux automática, segura e confiável. você pode usar um gerenciador de software GUI, como o GNOME Software, para ver e aplicar atualizações, a ferramenta de linha de comando ou a interface D-Bus diretamente." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "Este remoto contém firmware que não está embargado, mas ainda está sendo testado pelo fornecedor do hardware. Você deve garantir que você tenha uma maneira de fazer downgrade manual do firmware se a atualização do firmware falhar." @@ -840,6 +906,11 @@ msgstr "Soma de verificação da atualização" msgid "Update Description" msgstr "Descrição da atualização" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Duração da atualização" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Local da atualização" @@ -860,9 +931,6 @@ msgstr "Resumo da atualização" msgid "Update Version" msgstr "Versão da atualização" -msgid "Update device firmware on Linux" -msgstr "Atualize firmware de dispositivos no Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "A falha de atualização é um problema conhecido, visite essa URL para mais informações:" @@ -889,6 +957,11 @@ msgstr "Atualiza todos os firmwares para a última versão disponível" msgid "Updating %s from %s to %s... " msgstr "Atualizando %s de %s para %s… " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Atualizando %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Mensagem enviada:" @@ -940,6 +1013,3 @@ msgstr "Escrevendo…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Seu distribuidor pode não ter verificado qualquer das atualizações de firmware para compatibilidade com seu sistema ou dispositivos conectados." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/ru.po b/po/ru.po index be5d8dcad..01986bab5 100644 --- a/po/ru.po +++ b/po/ru.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Russian (http://www.transifex.com/freedesktop/fwupd/language/ru/)\n" "MIME-Version: 1.0\n" @@ -548,12 +548,6 @@ msgstr "Состояние" msgid "Status" msgstr "Статус" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Процесс fwupd является простой фоновой службой, позволяющей сеансовому программному обеспечению обновлять микропрограммы устройств на вашем компьютере. Он разработан для настольных компьютеров, но этот проект также годен для использования на телефонах, планшетах и безмониторных серверах." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Целью этого проекта является безопасная и надёжная автоматизация обновления микропрограмм в Linux. Для просмотра и применения обновлений вы можете использовать как графический диспетчер программного обеспечения, такой как GNOME Software, так и инструментарий командной строки или даже непосредственно D-Bus интерфейс." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Заголовок" @@ -601,9 +595,6 @@ msgstr "Удалённый ID обновления" msgid "Update Version" msgstr "Версия обновления" -msgid "Update device firmware on Linux" -msgstr "Обновить микропрограмму устройства на Linux" - msgid "Update the stored device verification information" msgstr "Обновление хранимой проверочной информации устройства" @@ -653,6 +644,3 @@ msgstr "Записать микропрограмму из файла на од #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Запись…" - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/sk.po b/po/sk.po index 257221444..4f55f8a8f 100644 --- a/po/sk.po +++ b/po/sk.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Slovak (http://www.transifex.com/freedesktop/fwupd/language/sk/)\n" "MIME-Version: 1.0\n" diff --git a/po/sr.po b/po/sr.po index a62d7be28..c7029da15 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Serbian (http://www.transifex.com/freedesktop/fwupd/language/sr/)\n" "MIME-Version: 1.0\n" @@ -632,12 +632,6 @@ msgstr "Сажетак" msgid "Target" msgstr "Мета" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Fwupd процес је једноставан демно који омогућава програмиму у сесији да ажурира фирмвер уређаја на вашој локалној машини. Намењен је за стоне рачунаре али је овај пројекат могуће користити на телефонима, таблетима и безглавим серверима." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Сврха овог пројекта је да учини ажурирање фирмвера на Линуксу лаким, безбедним и поузданим. Можете користити графичког управника програма као што су то Гномови Програми да бисте гледали и примењивали исправке, командну алатку или D-Bus интерфејс директно." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Наслов" @@ -693,9 +687,6 @@ msgstr "Сажетак ажурирања" msgid "Update Version" msgstr "Верзија ажурирања" -msgid "Update device firmware on Linux" -msgstr "Ажурирајте фирмвер уређаја на Линуксу" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Узрок неуспеха ажурирања је познат, погледајте ову адресу за више података:" @@ -761,6 +752,3 @@ msgstr "Упиши фирмвер из датотеке у једну парти #. TRANSLATORS: writing to the flash chips msgid "Writing…" msgstr "Пишем…" - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/sv.po b/po/sv.po index 8d9f4287a..ca08776a8 100644 --- a/po/sv.po +++ b/po/sv.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Swedish (http://www.transifex.com/freedesktop/fwupd/language/sv/)\n" "MIME-Version: 1.0\n" @@ -676,12 +676,6 @@ msgstr "Sammanfattning" msgid "Target" msgstr "Mål" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Fwupd-processen är en enkel demon som tillåter sessions-programvara att uppdatera enheters fasta programvara på din lokala maskin. Det är utformat för skrivbordsmiljöer, men detta projekt är också användbart på telefoner, surfplattor och skärmlösa servrar." - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Detta projekt strävar efter att göra uppdatering av fast programvara på Linux automatisk, säker och pålitlig. Du kan antingen använda ett grafiskt användargränssnitt som GNOME Programvara för att granska och applicera uppdateringar, ett kommandoradsverktyg eller direkt mot D-Bus gränssnittet." - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Titel" @@ -737,9 +731,6 @@ msgstr "Uppdateringssammanfattning" msgid "Update Version" msgstr "Uppdateringsversion" -msgid "Update device firmware on Linux" -msgstr "Uppdatera enhetens fasta programvara på Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Misslyckad uppdatering är ett känt fel, besök denna url för mer information:" @@ -813,6 +804,3 @@ msgstr "Skriver…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Din distributör kanske inte har verifierat någon av uppdateringarna av fastprogramvara för kompatibilitet med ditt system eller anslutna enheter." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/tr.po b/po/tr.po index 1377a3a9e..044d46eac 100644 --- a/po/tr.po +++ b/po/tr.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Turkish (http://www.transifex.com/freedesktop/fwupd/language/tr/)\n" "MIME-Version: 1.0\n" diff --git a/po/uk.po b/po/uk.po index dd01c2add..7a9702415 100644 --- a/po/uk.po +++ b/po/uk.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 12:46+0000\n" -"Last-Translator: Yuri Chornoivan \n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" +"Last-Translator: Richard Hughes \n" "Language-Team: Ukrainian (http://www.transifex.com/freedesktop/fwupd/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -32,6 +32,42 @@ msgstr[3] "Лишилася %.0f хвилина" msgid "%s has firmware updates:" msgstr "%s має такі оновлення мікропрограми:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u день" +msgstr[1] "%u дні" +msgstr[2] "%u днів" +msgstr[3] "%u день" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u година" +msgstr[1] "%u години" +msgstr[2] "%u годин" +msgstr[3] "%u година" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u хвилина" +msgstr[1] "%u хвилини" +msgstr[2] "%u хвилин" +msgstr[3] "%u хвилина" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u секунда" +msgstr[1] "%u секунди" +msgstr[2] "%u секунд" +msgstr[3] "%u секунда" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Додано" @@ -824,9 +860,6 @@ msgstr "Ціль" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS є безкоштовною службою, яка працює як незалежна юридична одиниця і не має зв'язку з $OS_RELEASE:NAME$. Розробники вашої операційної системи, можливо, не перевіряли жодні з цих оновлень на сумісність із системою або з'єднаними із комп'ютером пристроями. Усі мікропрограми надаються лише самими виробниками обладнання." -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "Процес fwupd є простою фоновою службою, яка надає змогу оновлювати мікропрограми пристроїв на вашому локальному комп’ютері у межах сеансу користування. Програму розроблено для робочих станцій, але нею можна скористатися на телефонах, планшетах та серверах без дисплеїв." - #. TRANSLATORS: exactly one update needs this msgid "The update requires a reboot to complete." msgstr "Для завершення оновлення потрібне перезавантаження." @@ -835,9 +868,6 @@ msgstr "Для завершення оновлення потрібне пере msgid "This program may only work correctly as root" msgstr "Програма зможе працювати належними чином лише від імені користувача root" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "Метою цього проекту є автоматизація оновлення мікропрограм обладнання у Linux, безпечно і надійно. Для перегляду і застосування оновлень ви можете скористатися або програмою для керування програмним забезпеченням, зокрема Програмними засобами GNOME, або інструментом командного рядка, або безпосередньо інтерфейсом D-Bus." - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "У цьому сховищі міститься мікропрограма, встановлювати яку не заборонено, але яка усе ще перебуває у процесі тестування виробником обладнання. Вам слід переконатися, що ви зможете встановити стабільну версію мікропрограми, якщо процедура оновлення зазнає невдачі." @@ -884,6 +914,11 @@ msgstr "Контрольна сума оновлення" msgid "Update Description" msgstr "Опис оновлення" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Тривалість оновлення" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Місце оновлення" @@ -904,9 +939,6 @@ msgstr "Резюме оновлення" msgid "Update Version" msgstr "Версія оновлення" -msgid "Update device firmware on Linux" -msgstr "Оновлення мікропрограм пристроїв у Linux" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Нам відомо про помилку під час оновлення. Будь ласка, відвідайте цю адресу, щоб дізнатися більше:" @@ -989,6 +1021,3 @@ msgstr "Записуємо…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "Виробник вашого дистрибутива може не перевіряти усі оновлення мікропрограми на сумісність із вашою системою або з’єднаними із нею пристроями." - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/zh_CN.po b/po/zh_CN.po index 65281a06b..cb57be863 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Chinese (China) (http://www.transifex.com/freedesktop/fwupd/language/zh_CN/)\n" "MIME-Version: 1.0\n" @@ -683,12 +683,6 @@ msgstr "概览" msgid "Target" msgstr "目标" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 的进程作为一个简单的守护程序,可以让会话软件更新您本地机器的设备固件。它为桌面环境设计,但该项目可以应用在手机、平板电脑和服务器上。" - -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "本项目的目标是让 Linux 上更新固件的流程变得自动化、安全又可靠。您既可以使用如 GNOME 软件这样的软件包管理器查看和应用更新,也可以直接使用命令行工具或者 D-Bus 接口。" - #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "标题" @@ -744,9 +738,6 @@ msgstr "更新概览" msgid "Update Version" msgstr "更新版本" -msgid "Update device firmware on Linux" -msgstr "更新 Linux 上的设备固件" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "更新失败为已知问题,请访问此 URL 以获取详情:" @@ -820,6 +811,3 @@ msgstr "正在写入…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "您的发行商可能尚未认证任何固件的系统及设备兼容性。" - -msgid "fwupd" -msgstr "fwupd" diff --git a/po/zh_TW.po b/po/zh_TW.po index 4b2976a20..913feef26 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" +"POT-Creation-Date: 2018-12-30 15:16+0000\n" +"PO-Revision-Date: 2018-11-28 13:44+0000\n" "Last-Translator: Richard Hughes \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/freedesktop/fwupd/language/zh_TW/)\n" "MIME-Version: 1.0\n" @@ -794,9 +794,6 @@ msgstr "目標" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS(Linux 廠商韌體服務,Linux Vendor Firmware Service)是由獨立法人運作的免費服務,而與 $OS_RELEASE:NAME$ 沒有關聯。您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。所有本服務中的韌體僅由原始設備製造商提供。" -msgid "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 程序是個簡易幕後程式,允許工作階段軟體更新您本地端機器上的裝置韌體。它主要設計給桌面電腦使用,但本專案也能用於手機、平板,或是指令列介面伺服器。" - #. TRANSLATORS: exactly one update needs this msgid "The update requires a reboot to complete." msgstr "更新必須重新開機才能完成。" @@ -805,9 +802,6 @@ msgstr "更新必須重新開機才能完成。" msgid "This program may only work correctly as root" msgstr "此程式僅有 root 身份才能正常運作" -msgid "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." -msgstr "本專案宗旨在於讓 Linux 上的韌體更新能自動、安全、可靠。您可以使用圖形介面的軟體管理員,如《GNOME 軟體》來檢視並套用更新,或用指令列工具,或甚至直接用 D-Bus 介面。" - msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." msgstr "這個遠端站點包含未列入禁運,但仍處於硬體廠商測試階段的韌體。您應該確保自己在韌體更新失敗時有方法能夠手動降級韌體。" @@ -874,9 +868,6 @@ msgstr "更新摘要" msgid "Update Version" msgstr "更新版本" -msgid "Update device firmware on Linux" -msgstr "在 Linux 上更新裝置韌體" - #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "更新失敗是已知議題,請造訪此 URL 瞭解更多資訊:" @@ -954,6 +945,3 @@ msgstr "寫入中…" #. TRANSLATORS: show the user a warning msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." msgstr "您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。" - -msgid "fwupd" -msgstr "fwupd" From fb0e10722a8e61c671f6baf81f41534e1b8950e7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 30 Dec 2018 15:23:27 +0000 Subject: [PATCH 150/254] trivial: post release version bump --- RELEASE | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE b/RELEASE index 45c4eb558..19c932209 100644 --- a/RELEASE +++ b/RELEASE @@ -2,7 +2,7 @@ fwupd Release Notes Write release entries: -git log --format="%s" --cherry-pick --right-only 1.2.1... | grep -i -v trivial | grep -v Merge | sort | uniq +git log --format="%s" --cherry-pick --right-only 1.2.2... | grep -i -v trivial | grep -v Merge | sort | uniq Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS @@ -19,7 +19,7 @@ git add ../po/*.po 2. Commit changes to git: # MAKE SURE THIS IS CORRECT -export release_ver="1.2.2" +export release_ver="1.2.3" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/meson.build b/meson.build index b3bcd6718..b6df98b3d 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.2.2', + version : '1.2.3', license : 'LGPL-2.1+', meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], From 305f1f2ab1dc460ebc243597ce9c70982f37a808 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 2 Jan 2019 09:50:39 +0000 Subject: [PATCH 151/254] trivial: Add some debugging data to wacom-usb --- plugins/wacom-usb/data/lsusb.txt | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 plugins/wacom-usb/data/lsusb.txt diff --git a/plugins/wacom-usb/data/lsusb.txt b/plugins/wacom-usb/data/lsusb.txt new file mode 100644 index 000000000..216f0b72c --- /dev/null +++ b/plugins/wacom-usb/data/lsusb.txt @@ -0,0 +1,58 @@ +Bus 001 Device 023: ID 056a:0378 Wacom Co., Ltd CTL-6100WL [Intuos BT (M)] +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x056a Wacom Co., Ltd + idProduct 0x0378 CTL-6100WL [Intuos BT (M)] + bcdDevice 1.66 + iManufacturer 1 Wacom Co.,Ltd. + iProduct 2 Intuos BT M + iSerial 3 8BH00U2012294 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0022 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 759 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) From f692b71dc4768f853a9c51f528abae15cbc2c1b0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 2 Jan 2019 20:18:14 +0000 Subject: [PATCH 152/254] Correctly migrate the history database I forgot to include the protocol column when migrating to v3, so create a v4 which ignores the sqlite error if the column already exists. Fixes https://github.com/hughsie/fwupd/issues/909 --- src/fu-history.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/fu-history.c b/src/fu-history.c index 0f90e0114..20709d853 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -157,7 +157,7 @@ fu_history_create_database (FuHistory *self, GError **error) "CREATE TABLE schema (" "created timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP," "version INTEGER DEFAULT 0);" - "INSERT INTO schema (version) VALUES (3);" + "INSERT INTO schema (version) VALUES (4);" "CREATE TABLE history (" "device_id TEXT," "update_state INTEGER DEFAULT 0," @@ -226,7 +226,8 @@ fu_history_migrate_database_v2 (FuHistory *self, GError **error) /* rename the table to something out the way */ rc = sqlite3_exec (self->db, - "ALTER TABLE history ADD COLUMN checksum_device TEXT DEFAULT NULL;", + "ALTER TABLE history ADD COLUMN checksum_device TEXT DEFAULT NULL;" + "ALTER TABLE history ADD COLUMN protocol TEXT DEFAULT NULL;", NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -236,7 +237,7 @@ fu_history_migrate_database_v2 (FuHistory *self, GError **error) } /* update version */ - rc = sqlite3_exec (self->db, "UPDATE schema SET version=3;", NULL, NULL, NULL); + rc = sqlite3_exec (self->db, "UPDATE schema SET version=4;", NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Failed to migrate database: %s", @@ -246,6 +247,29 @@ fu_history_migrate_database_v2 (FuHistory *self, GError **error) return TRUE; } +static gboolean +fu_history_migrate_database_v3 (FuHistory *self, GError **error) +{ + gint rc; + + /* rename the table to something out the way */ + rc = sqlite3_exec (self->db, + "ALTER TABLE history ADD COLUMN protocol TEXT DEFAULT NULL;", + NULL, NULL, NULL); + if (rc != SQLITE_OK) + g_debug ("ignoring database error: %s", sqlite3_errmsg (self->db)); + + /* update version */ + rc = sqlite3_exec (self->db, "UPDATE schema SET version=4;", NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to update schema version: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + /* returns 0 if database is not initialised */ static guint fu_history_get_schema_version (FuHistory *self) @@ -333,6 +357,10 @@ fu_history_load (FuHistory *self, GError **error) g_debug ("migrating v%u database", schema_ver); if (!fu_history_migrate_database_v2 (self, error)) return FALSE; + } else if (schema_ver == 3) { + g_debug ("migrating v%u database", schema_ver); + if (!fu_history_migrate_database_v3 (self, error)) + return FALSE; } return TRUE; From 36a5b8f7a26b881dd41cca2466618d5a29796a45 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 4 Jan 2019 11:08:49 +0000 Subject: [PATCH 153/254] Release fwupd 1.2.3 --- data/org.freedesktop.fwupd.metainfo.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 452a24de9..69241135d 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -31,6 +31,14 @@ moderate + + +

        This release fixes the following bug:

        +
          +
        • Correctly migrate the history database
        • +
        +
        +

        This release adds the following features:

        From 847959d89c6e7d07b058adeef9184985bf1825e8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 4 Jan 2019 11:09:50 +0000 Subject: [PATCH 154/254] trivial: post release version bump --- RELEASE | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE b/RELEASE index 19c932209..1ebc3c19c 100644 --- a/RELEASE +++ b/RELEASE @@ -2,7 +2,7 @@ fwupd Release Notes Write release entries: -git log --format="%s" --cherry-pick --right-only 1.2.2... | grep -i -v trivial | grep -v Merge | sort | uniq +git log --format="%s" --cherry-pick --right-only 1.2.3... | grep -i -v trivial | grep -v Merge | sort | uniq Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS @@ -19,7 +19,7 @@ git add ../po/*.po 2. Commit changes to git: # MAKE SURE THIS IS CORRECT -export release_ver="1.2.3" +export release_ver="1.2.4" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" diff --git a/meson.build b/meson.build index b6df98b3d..b95d7b042 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('fwupd', 'c', - version : '1.2.3', + version : '1.2.4', license : 'LGPL-2.1+', meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], From c9f46290bc531eb71f63968c25f3fcb9838e7333 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 7 Jan 2019 09:43:34 -0600 Subject: [PATCH 155/254] Add a new plugin checklist (Fixes: #899) --- .github/pull_request_template.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..b478bac1d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ +Type of pull request: +- [ ] New plugin (Please include [new plugin checklist](https://github.com/hughsie/fwupd/wiki/New-plugin-checklist)) +- [ ] Code fix +- [ ] Feature +- [ ] Documentation From 46bb4e91a015696e7713b2d8c214f6912be3d682 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 7 Jan 2019 09:44:31 -0600 Subject: [PATCH 156/254] fu-main: remove incompatible locale error message Downgrade this to debugging instead. (Fixes: #912) --- src/fu-main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/fu-main.c b/src/fu-main.c index e50cacb2d..98efb4135 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1255,7 +1255,6 @@ main (int argc, char *argv[]) g_autoptr(FuMainPrivate) priv = NULL; g_autoptr(GError) error = NULL; g_autoptr(GOptionContext) context = NULL; - g_autofree gchar *version_tmp = NULL; setlocale (LC_ALL, ""); @@ -1263,11 +1262,6 @@ main (int argc, char *argv[]) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); - /* test we're in a C-ish locale */ - version_tmp = g_strdup_printf ("%.2f", 1.23f); - if (g_strcmp0 (version_tmp, "1.23") != 0) - g_printerr ("Started with an incompatible locale!\n"); - /* TRANSLATORS: program name */ g_set_application_name (_("Firmware Update Daemon")); context = g_option_context_new (NULL); @@ -1345,6 +1339,8 @@ main (int argc, char *argv[]) else if (timed_exit) g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop); + g_debug ("Started with locale %s", g_getenv ("LANG")); + /* wait */ g_message ("Daemon ready for requests"); g_main_loop_run (priv->loop); From 3548186462d768daf301fd4d11981fa0ff687f89 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 6 Jan 2019 12:01:58 +0000 Subject: [PATCH 157/254] trivial: Make fu_common_dump_raw() more useful for debugging --- src/fu-common.c | 83 ++++++++++++++++++++++++++++++++++++++++++------- src/fu-common.h | 13 ++++++++ 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/src/fu-common.c b/src/fu-common.c index b567a73ab..d7f55ddaa 100644 --- a/src/fu-common.c +++ b/src/fu-common.c @@ -1065,6 +1065,74 @@ fu_common_string_replace (GString *string, const gchar *search, const gchar *rep return count; } +/** + * fu_common_dump_full: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @data: buffer to print + * @len: the size of @data + * @columns: break new lines after this many bytes + * @flags: some #FuDumpFlags, e.g. %FU_DUMP_FLAGS_SHOW_ASCII + * + * Dumps a raw buffer to the screen. + * + * Since: 1.2.4 + **/ +void +fu_common_dump_full (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len, + guint columns, + FuDumpFlags flags) +{ + g_autoptr(GString) str = g_string_new (NULL); + + /* optional */ + if (title != NULL) + g_string_append_printf (str, "%s:", title); + + /* if more than can fit on one line then start afresh */ + if (len > columns || flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) { + g_string_append (str, "\n"); + } else { + for (gsize i = str->len; i < 16; i++) + g_string_append (str, " "); + } + + /* offset line */ + if (flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) { + g_string_append (str, " │ "); + for (gsize i = 0; i < columns; i++) + g_string_append_printf (str, "%02x ", (guint) i); + g_string_append (str, "\n───────┼"); + for (gsize i = 0; i < columns; i++) + g_string_append (str, "───"); + g_string_append_printf (str, "\n0x%04x │ ", (guint) 0); + } + + /* print each row */ + for (gsize i = 0; i < len; i++) { + g_string_append_printf (str, "%02x ", data[i]); + + /* optionally print ASCII char */ + if (flags & FU_DUMP_FLAGS_SHOW_ASCII) { + if (g_ascii_isprint (data[i])) + g_string_append_printf (str, "[%c] ", data[i]); + else + g_string_append (str, "[?] "); + } + + /* new row required */ + if (i > 0 && i != len - 1 && (i + 1) % columns == 0) { + g_string_append (str, "\n"); + if (flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) + g_string_append_printf (str, "0x%04x │ ", (guint) i + 1); + } + } + g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", str->str); +} + /** * fu_common_dump_raw: * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL @@ -1082,17 +1150,10 @@ fu_common_dump_raw (const gchar *log_domain, const guint8 *data, gsize len) { - g_autoptr(GString) str = g_string_new (NULL); - if (title != NULL) - g_string_append_printf (str, "%s:", title); - for (gsize i = str->len; i < 16; i++) - g_string_append (str, " "); - for (gsize i = 0; i < len; i++) { - g_string_append_printf (str, "%02x ", data[i]); - if (i > 0 && i % 32 == 0) - g_string_append (str, "\n"); - } - g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", str->str); + FuDumpFlags flags = FU_DUMP_FLAGS_NONE; + if (len > 64) + flags |= FU_DUMP_FLAGS_SHOW_ADDRESSES; + fu_common_dump_full (log_domain, title, data, len, 32, flags); } /** diff --git a/src/fu-common.h b/src/fu-common.h index cfce057ea..5a2bfcc7e 100644 --- a/src/fu-common.h +++ b/src/fu-common.h @@ -15,6 +15,13 @@ typedef enum { FU_APP_FLAGS_LAST } FuAppFlags; +typedef enum { + FU_DUMP_FLAGS_NONE = 0, + FU_DUMP_FLAGS_SHOW_ASCII = 1 << 0, + FU_DUMP_FLAGS_SHOW_ADDRESSES = 1 << 1, + FU_DUMP_FLAGS_LAST +} FuDumpFlags; + typedef enum { FU_PATH_KIND_CACHEDIR_PKG, FU_PATH_KIND_DATADIR_PKG, @@ -70,6 +77,12 @@ void fu_common_dump_raw (const gchar *log_domain, const gchar *title, const guint8 *data, gsize len); +void fu_common_dump_full (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len, + guint columns, + FuDumpFlags flags); void fu_common_dump_bytes (const gchar *log_domain, const gchar *title, GBytes *bytes); From 831eb7ef7e60c91485a3953267cbfb416018a8d3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 6 Jan 2019 12:03:40 +0000 Subject: [PATCH 158/254] superio: Support IT89xx devices We can switch to LDN 0x11 and read the IO base address for the PM1 legacy port rather than hardcoding data and command ports. --- plugins/superio/fu-plugin-superio.c | 23 +-- plugins/superio/fu-superio-common.c | 102 +++++++++++++ plugins/superio/fu-superio-common.h | 51 +++++++ plugins/superio/fu-superio-device.c | 227 +++++++++++++++++----------- plugins/superio/fu-superio-device.h | 3 +- plugins/superio/meson.build | 1 + plugins/superio/superio.quirk | 19 +++ 7 files changed, 319 insertions(+), 107 deletions(-) create mode 100644 plugins/superio/fu-superio-common.c create mode 100644 plugins/superio/fu-superio-common.h diff --git a/plugins/superio/fu-plugin-superio.c b/plugins/superio/fu-plugin-superio.c index 27aa014ee..2135cd551 100644 --- a/plugins/superio/fu-plugin-superio.c +++ b/plugins/superio/fu-plugin-superio.c @@ -19,8 +19,7 @@ fu_plugin_superio_coldplug_chipset (FuPlugin *plugin, const gchar *chipset, GErr g_autoptr(FuDeviceLocker) locker = NULL; g_autofree gchar *key = g_strdup_printf ("SuperIO=%s", chipset); guint64 id; - guint64 data_port; - guint64 cmd_port; + guint64 port; /* get ID we need for the chipset */ id = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Id"); @@ -32,28 +31,18 @@ fu_plugin_superio_coldplug_chipset (FuPlugin *plugin, const gchar *chipset, GErr return FALSE; } - /* allow using a custom data port */ - data_port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "DataPort"); - if (data_port > 0xff) { + /* set address */ + port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Port"); + if (port == 0x0 || port > 0xffff) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "SuperIO chip %s has invalid DataPort", chipset); - return FALSE; - } - - /* allow using a custom command port */ - cmd_port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "CmdPort"); - if (cmd_port > 0xff) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "SuperIO chip %s has invalid CmdPort", chipset); + "SuperIO chip %s has invalid Port", chipset); return FALSE; } /* create device and unlock */ - dev = fu_superio_device_new (chipset, id, data_port, cmd_port); + dev = fu_superio_device_new (chipset, id, port); locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; diff --git a/plugins/superio/fu-superio-common.c b/plugins/superio/fu-superio-common.c new file mode 100644 index 000000000..85ea2ca00 --- /dev/null +++ b/plugins/superio/fu-superio-common.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-superio-common.h" + +gboolean +fu_superio_outb (gint fd, guint16 port, guint8 data, GError **error) +{ + if (pwrite (fd, &data, 1, (goffset) port) != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write to port %04x: %s", + (guint) port, + strerror (errno)); + return FALSE; + } + return TRUE; +} + +gboolean +fu_superio_inb (gint fd, guint16 port, guint8 *data, GError **error) +{ + if (pread (fd, data, 1, (goffset) port) != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read from port %04x: %s", + (guint) port, + strerror (errno)); + return FALSE; + } + return TRUE; +} + +gboolean +fu_superio_regval (gint fd, guint16 port, guint8 addr, + guint8 *data, GError **error) +{ + if (!fu_superio_outb (fd, port, addr, error)) + return FALSE; + if (!fu_superio_inb (fd, port + 1, data, error)) + return FALSE; + return TRUE; +} + +gboolean +fu_superio_regval16 (gint fd, guint16 port, guint8 addr, + guint16 *data, GError **error) +{ + guint8 msb; + guint8 lsb; + if (!fu_superio_regval (fd, port, addr, &msb, error)) + return FALSE; + if (!fu_superio_regval (fd, port, addr + 1, &lsb, error)) + return FALSE; + *data = ((guint16) msb << 8) | (guint16) lsb; + return TRUE; +} + +gboolean +fu_superio_regwrite (gint fd, guint16 port, guint8 addr, + guint8 data, GError **error) +{ + if (!fu_superio_outb (fd, port, addr, error)) + return FALSE; + if (!fu_superio_outb (fd, port + 1, data, error)) + return FALSE; + return TRUE; +} + +gboolean +fu_superio_set_ldn (gint fd, guint16 port, guint8 ldn, GError **error) +{ + return fu_superio_regwrite (fd, port, LDN_SEL, ldn, error); +} + +gboolean +fu_superio_regdump (gint fd, guint16 port, guint8 ldn, GError **error) +{ + g_autofree gchar *title = NULL; + guint8 buf[0xff] = { 0x00 }; + + /* set LDN */ + if (!fu_superio_set_ldn (fd, port, ldn, error)) + return FALSE; + for (guint i = 0x00; i < 0xff; i++) { + if (!fu_superio_regval (fd, port, i, &buf[i], error)) + return FALSE; + } + title = g_strdup_printf ("PORT:0x%04x LDN:0x%02x", port, ldn); + fu_common_dump_raw (G_LOG_DOMAIN, title, buf, 0x100); + return TRUE; +} diff --git a/plugins/superio/fu-superio-common.h b/plugins/superio/fu-superio-common.h new file mode 100644 index 000000000..ed2b9d2a4 --- /dev/null +++ b/plugins/superio/fu-superio-common.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_SUPERIO_COMMON_H +#define __FU_SUPERIO_COMMON_H + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define LDN_SEL 0x07 /* LDN select register */ +#define MAXLDN 0x14 /* maximum LDN */ + +gboolean fu_superio_outb (gint fd, + guint16 port, + guint8 data, + GError **error); +gboolean fu_superio_inb (gint fd, + guint16 port, + guint8 *data, + GError **error); +gboolean fu_superio_regval (gint fd, + guint16 port, + guint8 addr, + guint8 *data, + GError **error); +gboolean fu_superio_regval16 (gint fd, + guint16 port, + guint8 addr, + guint16 *data, + GError **error); +gboolean fu_superio_regwrite (gint fd, + guint16 port, + guint8 addr, + guint8 data, + GError **error); +gboolean fu_superio_regdump (gint fd, + guint16 port, + guint8 ldn, + GError **error); +gboolean fu_superio_set_ldn (gint fd, + guint16 port, + guint8 ldn, + GError **error); + +G_END_DECLS + +#endif /* __FU_SUPERIO_COMMON_H */ diff --git a/plugins/superio/fu-superio-device.c b/plugins/superio/fu-superio-device.c index 304dd1706..2e882c9cd 100644 --- a/plugins/superio/fu-superio-device.c +++ b/plugins/superio/fu-superio-device.c @@ -12,19 +12,26 @@ #include +#include "fu-superio-common.h" #include "fu-superio-device.h" -#define FU_PLUGIN_SUPERIO_TIMEOUT 5 /* s */ +#define FU_PLUGIN_SUPERIO_TIMEOUT 0.25 /* s */ #define KB_IBF (1 << 1) /* i/p buffer full */ #define KB_OBF (1 << 0) /* o/p buffer full */ +#define SIO_CMD_GET_PARAM 0x80 +#define SIO_CMD_SET_PARAM 0x81 +#define SIO_CMD_GET_NAME_STR 0x92 +#define SIO_CMD_GET_VERSION_STR 0x93 + struct _FuSuperioDevice { FuDevice parent_instance; gint fd; gchar *chipset; - guint16 data_port; - guint16 cmd_port; + guint16 port; + guint16 pm1_iobad0; + guint16 pm1_iobad1; guint16 id; guint32 size; }; @@ -38,60 +45,21 @@ fu_superio_device_to_string (FuDevice *device, GString *str) g_string_append (str, " FuSuperioDevice:\n"); g_string_append_printf (str, " fd:\t\t\t%i\n", self->fd); g_string_append_printf (str, " chipset:\t\t%s\n", self->chipset); - g_string_append_printf (str, " data-port:\t\t0x%04x\n", (guint) self->data_port); - g_string_append_printf (str, " cmd-port:\t\t0x%04x\n", (guint) self->cmd_port); g_string_append_printf (str, " id:\t\t\t0x%04x\n", (guint) self->id); + g_string_append_printf (str, " port:\t\t0x%04x\n", (guint) self->port); + g_string_append_printf (str, " pm1-iobad0:\t\t0x%04x\n", (guint) self->pm1_iobad0); + g_string_append_printf (str, " pm1-iobad1:\t\t0x%04x\n", (guint) self->pm1_iobad1); g_string_append_printf (str, " size:\t\t0x%04x\n", (guint) self->size); } -static gboolean -fu_superio_device_outb (FuSuperioDevice *self, guint16 port, guint8 data, GError **error) -{ - if (pwrite (self->fd, &data, 1, (goffset) port) != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write to port %04x: %s", - (guint) port, - strerror (errno)); - return FALSE; - } - return TRUE; -} - -static gboolean -fu_superio_device_inb (FuSuperioDevice *self, guint16 port, guint8 *data, GError **error) -{ - if (pread (self->fd, data, 1, (goffset) port) != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read from port %04x: %s", - (guint) port, - strerror (errno)); - return FALSE; - } - return TRUE; -} - static guint16 fu_superio_device_check_id (FuSuperioDevice *self, GError **error) { - guint8 msb; - guint8 lsb; guint16 id_tmp; - if (!fu_superio_device_outb (self, 0x2e, 0x20, error)) - return FALSE; - if (!fu_superio_device_inb (self, 0x2f, &msb, error)) - return FALSE; - if (!fu_superio_device_outb (self, 0x2e, 0x21, error)) - return FALSE; - if (!fu_superio_device_inb (self, 0x2f, &lsb, error)) - return FALSE; - /* check matches */ - id_tmp = ((guint16) msb << 8) | (guint16) lsb; + if (!fu_superio_regval16 (self->fd, self->port, 0x20, &id_tmp, error)) + return FALSE; if (self->id != id_tmp) { g_set_error (error, G_IO_ERROR, @@ -110,7 +78,7 @@ fu_superio_device_wait_for (FuSuperioDevice *self, guint8 mask, gboolean set, GE g_autoptr(GTimer) timer = g_timer_new (); do { guint8 status = 0x00; - if (!fu_superio_device_inb (self, self->cmd_port, &status, error)) + if (!fu_superio_inb (self->fd, self->pm1_iobad1, &status, error)) return FALSE; if (g_timer_elapsed (timer, NULL) > FU_PLUGIN_SUPERIO_TIMEOUT) break; @@ -127,27 +95,25 @@ fu_superio_device_wait_for (FuSuperioDevice *self, guint8 mask, gboolean set, GE } static gboolean -fu_superio_device_ec_cmd (FuSuperioDevice *self, guint8 data, GError **error) -{ - if (!fu_superio_device_wait_for (self, KB_IBF, FALSE, error)) - return FALSE; - return fu_superio_device_outb (self, self->cmd_port, data, error); -} - -static gboolean -fu_superio_device_ec_read (FuSuperioDevice *self, guint8 *data, GError **error) +fu_superio_device_ec_read (FuSuperioDevice *self, + guint16 port, + guint8 *data, + GError **error) { if (!fu_superio_device_wait_for (self, KB_OBF, TRUE, error)) return FALSE; - return fu_superio_device_inb (self, self->data_port, data, error); + return fu_superio_inb (self->fd, port, data, error); } static gboolean -fu_superio_device_ec_write (FuSuperioDevice *self, guint8 data, GError **error) +fu_superio_device_ec_write (FuSuperioDevice *self, + guint16 port, + guint8 data, + GError **error) { if (!fu_superio_device_wait_for (self, KB_IBF, FALSE, error)) return FALSE; - return fu_superio_device_outb (self, self->data_port, data, error); + return fu_superio_outb (self->fd, port, data, error); } static gboolean @@ -157,11 +123,11 @@ fu_superio_device_ec_flush (FuSuperioDevice *self, GError **error) g_autoptr(GTimer) timer = g_timer_new (); do { guint8 unused = 0; - if (!fu_superio_device_inb (self, self->cmd_port, &status, error)) + if (!fu_superio_inb (self->fd, self->pm1_iobad1, &status, error)) return FALSE; if ((status & KB_OBF) == 0) break; - if (!fu_superio_device_inb (self, self->data_port, &unused, error)) + if (!fu_superio_inb (self->fd, self->pm1_iobad0, &unused, error)) return FALSE; if (g_timer_elapsed (timer, NULL) > FU_PLUGIN_SUPERIO_TIMEOUT) { g_set_error_literal (error, @@ -177,22 +143,22 @@ fu_superio_device_ec_flush (FuSuperioDevice *self, GError **error) static gboolean fu_superio_device_ec_get_param (FuSuperioDevice *self, guint8 param, guint8 *data, GError **error) { - if (!fu_superio_device_ec_cmd (self, 0x80, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, SIO_CMD_GET_PARAM, error)) return FALSE; - if (!fu_superio_device_ec_write (self, param, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad0, param, error)) return FALSE; - return fu_superio_device_ec_read (self, data, error); + return fu_superio_device_ec_read (self, self->pm1_iobad0, data, error); } #if 0 static gboolean fu_superio_device_ec_set_param (FuSuperioDevice *self, guint8 param, guint8 data, GError **error) { - if (!fu_superio_device_ec_cmd (self, 0x81, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, SIO_CMD_SET_PARAM, error)) return FALSE; - if (!fu_superio_device_ec_write (self, param, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad0, param, error)) return FALSE; - return fu_superio_device_ec_write (self, data, error); + return fu_superio_device_ec_write (self, self->pm1_iobad0, data, error); } #endif @@ -200,11 +166,11 @@ static gchar * fu_superio_device_ec_get_str (FuSuperioDevice *self, guint8 idx, GError **error) { GString *str = g_string_new (NULL); - if (!fu_superio_device_ec_cmd (self, idx, error)) + if (!fu_superio_device_ec_write (self, self->pm1_iobad1, idx, error)) return NULL; for (guint i = 0; i < 0xff; i++) { guint8 c = 0; - if (!fu_superio_device_ec_read (self, &c, error)) + if (!fu_superio_device_ec_read (self, self->pm1_iobad0, &c, error)) return NULL; if (c == '$') break; @@ -248,35 +214,121 @@ fu_superio_device_probe (FuDevice *device, GError **error) } static gboolean -fu_superio_device_setup (FuDevice *device, GError **error) +fu_superio_device_setup_it85xx (FuSuperioDevice *self, GError **error) { - FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); guint8 size_tmp = 0; g_autofree gchar *name = NULL; g_autofree gchar *version = NULL; + /* get EC size */ + if (!fu_superio_device_ec_flush (self, error)) { + g_prefix_error (error, "failed to flush: "); + return FALSE; + } + if (!fu_superio_device_ec_get_param (self, 0xe5, &size_tmp, error)) { + g_prefix_error (error, "failed to get EC size: "); + return FALSE; + } + self->size = ((guint32) size_tmp) << 10; + + /* get EC strings */ + name = fu_superio_device_ec_get_str (self, SIO_CMD_GET_NAME_STR, error); + if (name == NULL) { + g_prefix_error (error, "failed to get EC name: "); + return FALSE; + } + fu_device_set_name (FU_DEVICE (self), name); + version = fu_superio_device_ec_get_str (self, SIO_CMD_GET_VERSION_STR, error); + if (version == NULL) { + g_prefix_error (error, "failed to get EC version: "); + return FALSE; + } + fu_device_set_version (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_superio_device_setup_it89xx (FuSuperioDevice *self, GError **error) +{ + guint8 version_tmp[2] = { 0x00 }; + g_autofree gchar *version = NULL; + + /* get version */ + if (!fu_superio_device_ec_flush (self, error)) { + g_prefix_error (error, "failed to flush: "); + return FALSE; + } + if (!fu_superio_device_ec_get_param (self, 0x00, &version_tmp[0], error)) { + g_prefix_error (error, "failed to get version major: "); + return FALSE; + } + if (!fu_superio_device_ec_get_param (self, 0x01, &version_tmp[1], error)) { + g_prefix_error (error, "failed to get version minor: "); + return FALSE; + } + version = g_strdup_printf ("%02u.%02u", version_tmp[0], version_tmp[1]); + fu_device_set_version (FU_DEVICE (self), version); + + /* FIXME: hardcoded */ + self->size = 0x20000; + return TRUE; +} + +static gboolean +fu_superio_device_setup (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + /* check ID is correct */ if (!fu_superio_device_check_id (self, error)) { g_prefix_error (error, "failed to probe id: "); return FALSE; } - /* get EC size */ - if (!fu_superio_device_ec_flush (self, error)) - return FALSE; - if (!fu_superio_device_ec_get_param (self, 0xe5, &size_tmp, error)) - return FALSE; - self->size = ((guint32) size_tmp) << 10; + /* dump LDNs */ + if (g_getenv ("FWUPD_SUPERIO_VERBOSE") != NULL) { + for (guint j = 0; j < MAXLDN; j++) { + if (!fu_superio_regdump (self->fd, self->port, j, error)) + return FALSE; + } + } - /* get EC strings */ - name = fu_superio_device_ec_get_str (self, 0x92, error); - if (name == NULL) + /* set Power Management I/F Channel 1 LDN */ + if (!fu_superio_set_ldn (self->fd, self->port, 0x11, error)) return FALSE; - fu_device_set_name (device, name); - version = fu_superio_device_ec_get_str (self, 0x93, error); - if (version == NULL) + + /* get the PM1 IOBAD0 address */ + if (!fu_superio_regval16 (self->fd, self->port, 0x60, &self->pm1_iobad0, error)) return FALSE; - fu_device_set_version (device, version); + + /* get the PM1 IOBAD1 address */ + if (!fu_superio_regval16 (self->fd, self->port, 0x62, &self->pm1_iobad1, error)) + return FALSE; + + /* dump PMC register map */ + if (g_getenv ("FWUPD_SUPERIO_VERBOSE") != NULL) { + guint8 buf[0xff] = { 0x00 }; + for (guint i = 0x00; i < 0xff; i++) { + g_autoptr(GError) error_local = NULL; + if (!fu_superio_device_ec_get_param (self, i, &buf[i], &error_local)) { + g_debug ("param: 0x%02x = %s", i, error_local->message); + continue; + } + } + fu_common_dump_raw (G_LOG_DOMAIN, "EC PMC Registers", buf, 0x100); + } + + /* IT85xx */ + if (self->id >> 8 == 0x85) { + if (!fu_superio_device_setup_it85xx (self, error)) + return FALSE; + } + + /* IT89xx */ + if (self->id >> 8 == 0x89) { + if (!fu_superio_device_setup_it89xx (self, error)) + return FALSE; + } /* success */ return TRUE; @@ -321,13 +373,12 @@ fu_superio_device_class_init (FuSuperioDeviceClass *klass) } FuSuperioDevice * -fu_superio_device_new (const gchar *chipset, guint16 id, guint8 data_port, guint8 cmd_port) +fu_superio_device_new (const gchar *chipset, guint16 id, guint16 port) { FuSuperioDevice *self; self = g_object_new (FU_TYPE_SUPERIO_DEVICE, NULL); self->chipset = g_strdup (chipset); self->id = id; - self->data_port = data_port > 0 ? data_port : 0x62; - self->cmd_port = cmd_port > 0 ? cmd_port : 0x66; + self->port = port; return self; } diff --git a/plugins/superio/fu-superio-device.h b/plugins/superio/fu-superio-device.h index b9288ba7d..de7722e67 100644 --- a/plugins/superio/fu-superio-device.h +++ b/plugins/superio/fu-superio-device.h @@ -16,8 +16,7 @@ G_DECLARE_FINAL_TYPE (FuSuperioDevice, fu_superio_device, FU, SUPERIO_DEVICE, Fu FuSuperioDevice *fu_superio_device_new (const gchar *chipset, guint16 id, - guint8 data_port, - guint8 cmd_port); + guint16 port); G_END_DECLS diff --git a/plugins/superio/meson.build b/plugins/superio/meson.build index fb27ac504..ecbfad547 100644 --- a/plugins/superio/meson.build +++ b/plugins/superio/meson.build @@ -8,6 +8,7 @@ shared_module('fu_plugin_superio', sources : [ 'fu-plugin-superio.c', 'fu-superio-device.c', + 'fu-superio-common.c', ], include_directories : [ include_directories('../..'), diff --git a/plugins/superio/superio.quirk b/plugins/superio/superio.quirk index 019c63ca3..d1fa268c0 100644 --- a/plugins/superio/superio.quirk +++ b/plugins/superio/superio.quirk @@ -6,23 +6,42 @@ SuperioChipsets=IT8587 [HwId=f00d8c4e-dce2-51c3-89d6-6cbc5fc5cdbb] SuperioChipsets=IT8587 +# Star LabTop Mk3 +[HwId=3dc52d2c-9e9b-5ba5-b10d-9ba1eb11dacc] +SuperioChipsets=IT8987 + +# Star Lite Mk2 +[HwId=d1a64840-4307-58fb-a62c-de28a07c0151] +SuperioChipsets=IT8987 + [SuperIO=IT8510] Id=0x8510 +Port=0x2e [SuperIO=IT8511] Id=0x8511 +Port=0x2e [SuperIO=IT8512] Id=0x8512 +Port=0x2e [SuperIO=IT8513] Id=0x8513 +Port=0x2e [SuperIO=IT8516] Id=0x8516 +Port=0x2e [SuperIO=IT8518] Id=0x8518 +Port=0x2e [SuperIO=IT8587] Id=0x8587 +Port=0x2e + +[SuperIO=IT8987] +Id=0x8987 +Port=0x4e From b4e3698cfb47e79a996c937a318a43f5f338d296 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 8 Jan 2019 10:17:28 -0600 Subject: [PATCH 159/254] dell-dock: Wait longer for re-enumeration on TBT SKU Emperically this seems to take 7-10 seconds longer on this SKU. --- plugins/dell-dock/fu-dell-dock-common.c | 8 +++++--- plugins/dell-dock/fu-dell-dock-common.h | 1 - plugins/dell-dock/fu-dell-dock-i2c-ec.c | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/dell-dock/fu-dell-dock-common.c b/plugins/dell-dock/fu-dell-dock-common.c index d56ac15bb..6f4414d49 100644 --- a/plugins/dell-dock/fu-dell-dock-common.c +++ b/plugins/dell-dock/fu-dell-dock-common.c @@ -47,10 +47,12 @@ fu_dell_dock_set_power (FuDevice *device, guint8 target, void fu_dell_dock_will_replug (FuDevice *device) { + guint64 timeout = fu_device_get_install_duration (device); + g_return_if_fail (FU_IS_DEVICE (device)); - g_debug ("Activated %ds replug delay for %s", - REPLUG_TIMEOUT, fu_device_get_name (device)); - fu_device_set_remove_delay (device, REPLUG_TIMEOUT * 1000); + g_debug ("Activated %" G_GUINT64_FORMAT "s replug delay for %s", + timeout, fu_device_get_name (device)); + fu_device_set_remove_delay (device, timeout * 1000); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); } diff --git a/plugins/dell-dock/fu-dell-dock-common.h b/plugins/dell-dock/fu-dell-dock-common.h index 66560b72c..8f132b5a8 100644 --- a/plugins/dell-dock/fu-dell-dock-common.h +++ b/plugins/dell-dock/fu-dell-dock-common.h @@ -27,7 +27,6 @@ #define DELL_DOCK_EC_GUID "USB\\VID_413C&PID_B06E&hub&embedded" #define DELL_DOCK_TBT_GUID "TBT-00d4b070" -#define REPLUG_TIMEOUT 60 /* s */ gboolean fu_dell_dock_set_power (FuDevice *device, guint8 target, diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 893e8e017..ac9d5f30f 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -369,6 +369,12 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, } } + /* Thunderbolt SKU takes a little longer */ + if (self->data->module_type == MODULE_TYPE_TBT) { + guint64 tmp = fu_device_get_install_duration (device); + fu_device_set_install_duration (device, tmp + 20); + } + /* minimum EC version this code will support */ if (fu_common_vercmp (self->ec_version, self->ec_minimum_version) < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, From 993fc1636ceb1d328d9e04cef0830ff2271cb458 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 8 Jan 2019 09:47:29 -0600 Subject: [PATCH 160/254] dell-dock: Workaround a manufacturing bug for board level 4 Board 4 was manufactured with package version 89.16.01.00 and this will prevent properly upgrading between releases. Reset this version to 00.00.00.00 if detected on this board. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index ac9d5f30f..4ce22448d 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -593,6 +593,16 @@ guint32 fu_dell_dock_ec_get_status_version (FuDevice *device) { FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + /* TODO: drop if setting minimum board to 5+ + * this board was manufactured with 89.16.01.00 and won't upgrade + */ + if (self->data->board_id == 4 && + self->raw_versions->pkg_version == 71305) { + g_printerr ("Dock manufactured w/ invalid package %u\n", + self->raw_versions->pkg_version); + self->raw_versions->pkg_version = 0; + } return self->raw_versions->pkg_version; } From 8963d6b4b2ec52f83caeea4627a38c85550f17b2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 8 Jan 2019 09:29:14 -0600 Subject: [PATCH 161/254] dell-dock: Set minimum board to board 4 This allows dropping all the quirks related to older boards. --- plugins/dell-dock/dell-dock.quirk | 15 ++-------- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 12 -------- plugins/dell-dock/fu-dell-dock-i2c-mst.c | 38 ------------------------ 3 files changed, 2 insertions(+), 63 deletions(-) diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk index 5ec659f5d..199d430f7 100644 --- a/plugins/dell-dock/dell-dock.quirk +++ b/plugins/dell-dock/dell-dock.quirk @@ -70,8 +70,8 @@ FirmwareSizeMax = 0x20000 Flags = require-ac Children = FuDellDockStatus|USB\VID_413C&PID_B06E&hub&status,FuDellDockMst|MST-panamera-vmm5331-259 DellDockUnlockTarget = 1 -DellDockBoardMin = 2 -DellDockVersionLowest = 00.00.00.09 +DellDockBoardMin = 4 +DellDockVersionLowest = 00.00.00.17 DellDockBlobVersionOffset = 0x1AFC0 InstallDuration = 60 @@ -114,14 +114,3 @@ FirmwareSizeMin=0x40000 FirmwareSizeMax=0x80000 Flags = require-ac InstallDuration = 22 - -# Thunderbolt controller (old ID) -# TODO: This should be dropped when DellDockBoardMin is 3+ -[Guid=TBT-00d40012] -Name = Thunderbolt controller in Dell dock -Summary = Thunderbolt controller -Vendor = Dell Inc -ParentGuid = USB\VID_413C&PID_B06E&hub&embedded -FirmwareSizeMin=0x40000 -FirmwareSizeMax=0x80000 -Flags = require-ac,ignore-validation diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 4ce22448d..70b95afba 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -529,7 +529,6 @@ fu_dell_dock_ec_reset (FuDevice *device, GError **error) gboolean fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) { - FuDellDockEc *self = FU_DELL_DOCK_EC (device); guint16 cmd = EC_CMD_REBOOT; g_return_val_if_fail (device != NULL, FALSE); @@ -539,10 +538,6 @@ fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) return TRUE; } - /* TODO: Drop when bumping minimum EC version to 13+ */ - if (fu_common_vercmp (self->ec_version, "00.00.00.13") < 0) - g_print ("\nEC Reboot API may fail on EC %s. Please manually power cycle dock.\n", - self->ec_version); g_debug ("Rebooting %s", fu_device_get_name (device)); return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); @@ -634,13 +629,6 @@ fu_dell_dock_ec_commit_package (FuDevice *device, GBytes *blob_fw, g_debug ("\ttbt_version: %x", self->raw_versions->tbt_version); g_debug ("\tpkg_version: %x", self->raw_versions->pkg_version); - /* TODO: Drop when updating minimum EC to 11+ */ - if (fu_common_vercmp (self->ec_version, "00.00.00.11") < 0) { - g_debug ("EC %s doesn't support package version, ignoring", - self->ec_version); - return TRUE; - } - payload [0] = EC_CMD_SET_DOCK_PKG; payload [1] = length; memcpy (payload + 2, data, length); diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index 0fc07cfb4..5ceb848af 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -424,35 +424,6 @@ fu_d19_mst_check_fw (FuDevice *symbiote, GError **error) return TRUE; } -static gboolean -fu_dell_dock_mst_get_version_direct (FuDevice *symbiote, gchar **version_out, - GError **error) -{ - g_autoptr(GBytes) bytes = NULL; - const guint8 *data; - gsize length = 4; - - g_return_val_if_fail (version_out != NULL, FALSE); - - /* Try to read core MCU FW version */ - if (!fu_dell_dock_mst_read_register (symbiote, - MST_CORE_MCU_FW_VERSION, - length, &bytes, - error)) - return FALSE; - data = g_bytes_get_data (bytes, &length); - if (length < 4) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid MST result %" G_GSIZE_FORMAT, length); - return FALSE; - } - *version_out = g_strdup_printf ("%02x.%02x.%02x", - data[1], /* major */ - data[0], /* minor */ - data[2]); /* build */ - return TRUE; -} - static gboolean fu_dell_dock_mst_checksum_bank (FuDevice *symbiote, GBytes *blob_fw, @@ -923,7 +894,6 @@ fu_dell_dock_mst_setup (FuDevice *device, GError **error) FuDellDockMst *self = FU_DELL_DOCK_MST (device); FuDevice *parent; const gchar *version; - g_autofree gchar *dynamic_version = NULL; /* sanity check that we can talk to MST */ if (!fu_d19_mst_check_fw (self->symbiote, error)) @@ -933,14 +903,6 @@ fu_dell_dock_mst_setup (FuDevice *device, GError **error) parent = fu_device_get_parent (device); version = fu_dell_dock_ec_get_mst_version (parent); - /* TODO: Drop when we can guarantee EC 15+ */ - if (version == NULL) { - if (!fu_dell_dock_mst_get_version_direct (self->symbiote, - &dynamic_version, - error)) - return FALSE; - version = dynamic_version; - } if (version != NULL) fu_device_set_version (device, version); From 84e948a5b0aa4ee62183fb8c566a3d6f741e853c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Jan 2019 13:44:48 -0600 Subject: [PATCH 162/254] trivial: dell-dock: correct an assertion related to setting EC version This is probably fall out from a previous code re-shuffling. The EC version is already set elsewhere, and in many cases `self->ec_version` is `NULL` at this time. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 70b95afba..ff5f4c359 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -443,7 +443,6 @@ fu_dell_dock_ec_get_dock_data (FuDevice *device, /* make sure this hardware spin matches our expecations */ if (self->data->board_id >= self->board_min) { fu_dell_dock_ec_set_board (device); - fu_device_set_version (device, self->ec_version); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); } else { g_warning ("This utility does not support this board, disabling updates for %s", From baa5af4504700e36cc97f46ffe8b4c4beb40d901 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Jan 2019 12:54:06 -0600 Subject: [PATCH 163/254] trivial: fu-engine: Clarify the message when no releases are available --- src/fu-engine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index f5df88ba1..d5d931635 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2531,7 +2531,8 @@ fu_engine_get_releases_for_device (FuEngine *self, FuDevice *device, GError **er g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, - "No releases found for device"); + "No releases for %s", + fu_device_get_name (device)); return NULL; } g_propagate_error (error, g_steal_pointer (&error_local)); From 46aaee8cecef903bca792de70a4522e4f46398a4 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Jan 2019 12:58:00 -0600 Subject: [PATCH 164/254] fu-tool: Add support for an 'update' command to fwupdtool This will perform updates with all currently present metadata. It is "intended" for usage with local metadata repositories referring to local files. fwupdtool however does also support fetching a file from the web and if the metadata refers to the file on the web it should also work for that. --- data/bash-completion/fwupdtool.in | 1 + data/remotes.d/README.md | 2 +- src/fu-engine.c | 38 ++++++++++++++++ src/fu-engine.h | 3 ++ src/fu-tool.c | 72 +++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 86758ce0c..bd0216916 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -5,6 +5,7 @@ _fwupdtool_cmd_list=( 'get-plugins' 'get-topology' 'hwids' + 'update' 'install' 'install-blob' 'monitor' diff --git a/data/remotes.d/README.md b/data/remotes.d/README.md index d75e34d20..4571351d5 100644 --- a/data/remotes.d/README.md +++ b/data/remotes.d/README.md @@ -6,7 +6,7 @@ These are the steps to add vendor that is installed as part of an OSTree image: * Change `/etc/fwupd/remotes.d/vendor.conf` to have `Enabled=true` * Change `/etc/fwupd/remotes.d/vendor.conf` to have the correct `Title` * Deploy the firmware to `/usr/share/fwupd/remotes.d/vendor/firmware` -* Deploy the metadata to `/usr/share/fwupd/remotes.d/vendor/vendor.xml` +* Deploy the metadata to `/usr/share/fwupd/remotes.d/vendor/vendor.xml.gz` The metadata should be of the form: diff --git a/src/fu-engine.c b/src/fu-engine.c index d5d931635..05ebcf756 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -70,6 +70,7 @@ struct _FuEngine FuQuirks *quirks; GHashTable *runtime_versions; GHashTable *compile_versions; + gboolean loaded; }; enum { @@ -2420,6 +2421,38 @@ fu_engine_get_remotes (FuEngine *self, GError **error) return g_ptr_array_ref (remotes); } +/** + * fu_engine_get_remote_by_id: + * @self: A #FuEngine + * @remote_id: A string representation of a remote + * @error: A #GError, or %NULL + * + * Gets the FwupdRemote object. + * + * Returns: FwupdRemote + **/ +FwupdRemote * +fu_engine_get_remote_by_id (FuEngine *self, const gchar *remote_id, GError **error) +{ + g_autoptr(GPtrArray) remotes = NULL; + + remotes = fu_engine_get_remotes (self, error); + if (remotes == NULL) + return NULL; + + for (guint i = 0; i < remotes->len; i++) { + FwupdRemote *remote = g_ptr_array_index (remotes, i); + if (g_strcmp0 (remote_id, fwupd_remote_get_id (remote)) == 0) + return remote; + } + + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Couldn't find remote %s", remote_id); + + return NULL; +} + + static gint fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b) { @@ -3769,6 +3802,10 @@ fu_engine_load (FuEngine *self, GError **error) g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* avoid re-loading a second time if fu-tool or fu-util request to */ + if (self->loaded) + return TRUE; + /* read config file */ if (!fu_config_load (self->config, error)) { g_prefix_error (error, "Failed to load config: "); @@ -3855,6 +3892,7 @@ fu_engine_load (FuEngine *self, GError **error) return FALSE; fu_engine_set_status (self, FWUPD_STATUS_IDLE); + self->loaded = TRUE; /* success */ return TRUE; diff --git a/src/fu-engine.h b/src/fu-engine.h index b21d84075..67376e652 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -43,6 +43,9 @@ FuDevice *fu_engine_get_device (FuEngine *self, GError **error); GPtrArray *fu_engine_get_history (FuEngine *self, GError **error); +FwupdRemote *fu_engine_get_remote_by_id (FuEngine *self, + const gchar *remote_id, + GError **error); GPtrArray *fu_engine_get_remotes (FuEngine *self, GError **error); GPtrArray *fu_engine_get_releases (FuEngine *self, diff --git a/src/fu-tool.c b/src/fu-tool.c index 5cc423d12..dfd4193ae 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -753,6 +753,72 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, error)) + return FALSE; + + devices = fu_engine_get_devices (priv->engine, error); + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + FwupdRelease *rel; + const gchar *remote_id; + const gchar *device_id; + const gchar *uri_tmp; + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GError) error_local = NULL; + + if (!fu_util_is_interesting_device (dev)) + continue; + /* only show stuff that has metadata available */ + if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) + continue; + + device_id = fu_device_get_id (dev); + rels = fu_engine_get_upgrades (priv->engine, device_id, &error_local); + if (rels == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + + rel = g_ptr_array_index (rels, 0); + uri_tmp = fwupd_release_get_uri (rel); + remote_id = fwupd_release_get_remote_id (rel); + if (remote_id != NULL) { + FwupdRemote *remote; + g_auto(GStrv) argv = NULL; + + remote = fu_engine_get_remote_by_id (priv->engine, + remote_id, + &error_local); + if (remote == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + + argv = g_new0 (gchar *, 2); + /* local remotes have the firmware already */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); + g_autofree gchar *path = g_path_get_dirname (fn_cache); + argv[0] = g_build_filename (path, uri_tmp, NULL); + /* web remote, fu_util_install will download file */ + } else { + argv[0] = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); + } + if (!fu_util_install (priv, argv, &error_local)) { + g_printerr ("%s\n", error_local->message); + continue; + } + } + } + return TRUE; +} + static gboolean fu_util_detach (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1125,6 +1191,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Monitor the daemon for events"), fu_util_monitor); + fu_util_add (priv->cmd_array, + "update", + NULL, + /* TRANSLATORS: command description */ + _("Update all devices that match local metadata"), + fu_util_update); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); From 18f3ab4e4dec487429eccb2601673eb6e5e74367 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 14 Jan 2019 17:06:55 -0600 Subject: [PATCH 165/254] trivial: dell-dock: Prohibit downgrades on board 4 or later below EC19 Some SKUs of board 4 and later have silicon that will not work with anything but EC19 or later. So once flashed up to EC19 prohibit downgrades below that to keep from bricking devices. --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index ff5f4c359..5c3f95e67 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -383,6 +383,18 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, return FALSE; } + /* TODO: Drop if setting minimum board to 5+ and minimum EC to 19+ + * If running on board 4 or later, already EC19+, then + * don't allow downgrades to anything < EC19 + */ + if (self->data->board_id >= 4 && + fu_common_vercmp (self->ec_version, "00.00.00.19") >= 0) { + g_debug ("Prohibiting downgrades below EC 00.00.00.19"); + g_free (self->ec_minimum_version); + self->ec_minimum_version = g_strdup ("00.00.00.19"); + } + fu_device_set_version_lowest (device, self->ec_minimum_version); + return TRUE; } From fa8b7aab0a77a044cd5e8fc05c03fc4b5d55dd15 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 15 Jan 2019 14:56:00 +0000 Subject: [PATCH 166/254] nvme: Check the return code of the admin passthru ioctl This meant we reported firmware update success when the image format or offset was incorrect. --- plugins/nvme/fu-nvme-common.c | 140 ++++++++++++++++++++++++++++++++++ plugins/nvme/fu-nvme-common.h | 129 +++++++++++++++++++++++++++++++ plugins/nvme/fu-nvme-device.c | 29 ++++++- plugins/nvme/meson.build | 2 + 4 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 plugins/nvme/fu-nvme-common.c create mode 100644 plugins/nvme/fu-nvme-common.h diff --git a/plugins/nvme/fu-nvme-common.c b/plugins/nvme/fu-nvme-common.c new file mode 100644 index 000000000..830fab0f8 --- /dev/null +++ b/plugins/nvme/fu-nvme-common.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-nvme-common.h" + +const gchar * +fu_nvme_status_to_string (guint32 status) +{ + switch (status) { + case NVME_SC_SUCCESS: + return "Command completed successfully"; + case NVME_SC_INVALID_OPCODE: + return "Associated command opcode field is not valid"; + case NVME_SC_INVALID_FIELD: + return "Unsupported value in a defined field"; + case NVME_SC_CMDID_CONFLICT: + return "Command identifier is already in use"; + case NVME_SC_DATA_XFER_ERROR: + return "Error while trying to transfer the data or metadata"; + case NVME_SC_POWER_LOSS: + return "Command aborted due to power loss notification"; + case NVME_SC_INTERNAL: + return "Internal error"; + case NVME_SC_ABORT_REQ: + return "Command Abort request"; + case NVME_SC_ABORT_QUEUE: + return "Delete I/O Submission Queue request"; + case NVME_SC_FUSED_FAIL: + return "Other command in a fused operation failing"; + case NVME_SC_FUSED_MISSING: + return "Missing Fused Command"; + case NVME_SC_INVALID_NS: + return "Namespace or the format of that namespace is invalid"; + case NVME_SC_CMD_SEQ_ERROR: + return "Protocol violation in a multicommand sequence"; + case NVME_SC_SANITIZE_FAILED: + return "No recovery actions has been successfully completed"; + case NVME_SC_SANITIZE_IN_PROGRESS: + return "A sanitize operation is in progress"; + case NVME_SC_LBA_RANGE: + return "LBA exceeds the size of the namespace"; + case NVME_SC_NS_WRITE_PROTECTED: + return "Namespace is write protected by the host"; + case NVME_SC_CAP_EXCEEDED: + return "Capacity of the namespace to be exceeded"; + case NVME_SC_NS_NOT_READY: + return "Namespace is not ready to be accessed"; + case NVME_SC_RESERVATION_CONFLICT: + return "Conflict with a reservation on the accessed namespace"; + case NVME_SC_CQ_INVALID: + return "Completion Queue does not exist"; + case NVME_SC_QID_INVALID: + return "Invalid queue identifier specified"; + case NVME_SC_QUEUE_SIZE: + return "Invalid queue size"; + case NVME_SC_ABORT_LIMIT: + return "Outstanding Abort commands has exceeded the limit"; + case NVME_SC_ABORT_MISSING: + return "Abort command is missing"; + case NVME_SC_ASYNC_LIMIT: + return "Outstanding Async commands has been exceeded"; + case NVME_SC_FIRMWARE_SLOT: + return "Slot is invalid or read only"; + case NVME_SC_FIRMWARE_IMAGE: + return "Image specified for activation is invalid"; + case NVME_SC_INVALID_VECTOR: + return "Creation failed due to an invalid interrupt vector"; + case NVME_SC_INVALID_LOG_PAGE: + return "Log page indicated is invalid"; + case NVME_SC_INVALID_FORMAT: + return "LBA Format specified is not supported"; + case NVME_SC_FW_NEEDS_CONV_RESET: + return "commit was successful, but activation requires reset"; + case NVME_SC_INVALID_QUEUE: + return "Failed to delete the I/O Completion Queue specified"; + case NVME_SC_FEATURE_NOT_SAVEABLE: + return "Feature Identifier does not support a saveable value"; + case NVME_SC_FEATURE_NOT_CHANGEABLE: + return "Feature Identifier is not able to be changed"; + case NVME_SC_FEATURE_NOT_PER_NS: + return "Feature Identifier specified is not namespace specific"; + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + return "Commit was successful, activation requires NVM Subsystem"; + case NVME_SC_FW_NEEDS_RESET: + return "Commit was successful, activation requires a reset"; + case NVME_SC_FW_NEEDS_MAX_TIME: + return "Would exceed the Maximum Time for Firmware Activation"; + case NVME_SC_FW_ACIVATE_PROHIBITED: + return "Image specified is being prohibited from activation"; + case NVME_SC_OVERLAPPING_RANGE: + return "Image has overlapping ranges"; + case NVME_SC_NS_INSUFFICENT_CAP: + return "Requires more free space than is currently available"; + case NVME_SC_NS_ID_UNAVAILABLE: + return "Number of namespaces supported has been exceeded"; + case NVME_SC_NS_ALREADY_ATTACHED: + return "Controller is already attached to the namespace"; + case NVME_SC_NS_IS_PRIVATE: + return "Namespace is private"; + case NVME_SC_NS_NOT_ATTACHED: + return "Controller is not attached to the namespace"; + case NVME_SC_THIN_PROV_NOT_SUPP: + return "Thin provisioning is not supported by the controller"; + case NVME_SC_CTRL_LIST_INVALID: + return "Controller list provided is invalid"; + case NVME_SC_BP_WRITE_PROHIBITED: + return "Trying to modify a Boot Partition while it is locked"; + case NVME_SC_BAD_ATTRIBUTES: + return "Bad attributes"; + case NVME_SC_WRITE_FAULT: + return "Write data could not be committed to the media"; + case NVME_SC_READ_ERROR: + return "Read data could not be recovered from the media"; + case NVME_SC_GUARD_CHECK: + return "End-to-end guard check failure"; + case NVME_SC_APPTAG_CHECK: + return "End-to-end application tag check failure"; + case NVME_SC_REFTAG_CHECK: + return "End-to-end reference tag check failure"; + case NVME_SC_COMPARE_FAILED: + return "Miscompare during a Compare command"; + case NVME_SC_ACCESS_DENIED: + return "Access denied"; + case NVME_SC_UNWRITTEN_BLOCK: + return "Read from an LBA range containing a unwritten block"; + case NVME_SC_ANA_PERSISTENT_LOSS: + return "Namespace is in the ANA Persistent Loss state"; + case NVME_SC_ANA_INACCESSIBLE: + return "Namespace being in the ANA Inaccessible state"; + case NVME_SC_ANA_TRANSITION: + return "Namespace transitioning between Async Access states"; + default: + return "Unknown"; + } +} diff --git a/plugins/nvme/fu-nvme-common.h b/plugins/nvme/fu-nvme-common.h new file mode 100644 index 000000000..0cdac7782 --- /dev/null +++ b/plugins/nvme/fu-nvme-common.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_NVME_COMMON_H +#define __FU_NVME_COMMON_H + +#include + +G_BEGIN_DECLS + +enum { + /* + * Generic Command Status: + */ + NVME_SC_SUCCESS = 0x0, + NVME_SC_INVALID_OPCODE = 0x1, + NVME_SC_INVALID_FIELD = 0x2, + NVME_SC_CMDID_CONFLICT = 0x3, + NVME_SC_DATA_XFER_ERROR = 0x4, + NVME_SC_POWER_LOSS = 0x5, + NVME_SC_INTERNAL = 0x6, + NVME_SC_ABORT_REQ = 0x7, + NVME_SC_ABORT_QUEUE = 0x8, + NVME_SC_FUSED_FAIL = 0x9, + NVME_SC_FUSED_MISSING = 0xa, + NVME_SC_INVALID_NS = 0xb, + NVME_SC_CMD_SEQ_ERROR = 0xc, + NVME_SC_SGL_INVALID_LAST = 0xd, + NVME_SC_SGL_INVALID_COUNT = 0xe, + NVME_SC_SGL_INVALID_DATA = 0xf, + NVME_SC_SGL_INVALID_METADATA = 0x10, + NVME_SC_SGL_INVALID_TYPE = 0x11, + + NVME_SC_SGL_INVALID_OFFSET = 0x16, + NVME_SC_SGL_INVALID_SUBTYPE = 0x17, + + NVME_SC_SANITIZE_FAILED = 0x1C, + NVME_SC_SANITIZE_IN_PROGRESS = 0x1D, + + NVME_SC_NS_WRITE_PROTECTED = 0x20, + + NVME_SC_LBA_RANGE = 0x80, + NVME_SC_CAP_EXCEEDED = 0x81, + NVME_SC_NS_NOT_READY = 0x82, + NVME_SC_RESERVATION_CONFLICT = 0x83, + + /* + * Command Specific Status: + */ + NVME_SC_CQ_INVALID = 0x100, + NVME_SC_QID_INVALID = 0x101, + NVME_SC_QUEUE_SIZE = 0x102, + NVME_SC_ABORT_LIMIT = 0x103, + NVME_SC_ABORT_MISSING = 0x104, + NVME_SC_ASYNC_LIMIT = 0x105, + NVME_SC_FIRMWARE_SLOT = 0x106, + NVME_SC_FIRMWARE_IMAGE = 0x107, + NVME_SC_INVALID_VECTOR = 0x108, + NVME_SC_INVALID_LOG_PAGE = 0x109, + NVME_SC_INVALID_FORMAT = 0x10a, + NVME_SC_FW_NEEDS_CONV_RESET = 0x10b, + NVME_SC_INVALID_QUEUE = 0x10c, + NVME_SC_FEATURE_NOT_SAVEABLE = 0x10d, + NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e, + NVME_SC_FEATURE_NOT_PER_NS = 0x10f, + NVME_SC_FW_NEEDS_SUBSYS_RESET = 0x110, + NVME_SC_FW_NEEDS_RESET = 0x111, + NVME_SC_FW_NEEDS_MAX_TIME = 0x112, + NVME_SC_FW_ACIVATE_PROHIBITED = 0x113, + NVME_SC_OVERLAPPING_RANGE = 0x114, + NVME_SC_NS_INSUFFICENT_CAP = 0x115, + NVME_SC_NS_ID_UNAVAILABLE = 0x116, + NVME_SC_NS_ALREADY_ATTACHED = 0x118, + NVME_SC_NS_IS_PRIVATE = 0x119, + NVME_SC_NS_NOT_ATTACHED = 0x11a, + NVME_SC_THIN_PROV_NOT_SUPP = 0x11b, + NVME_SC_CTRL_LIST_INVALID = 0x11c, + NVME_SC_BP_WRITE_PROHIBITED = 0x11e, + + /* + * I/O Command Set Specific - NVM commands: + */ + NVME_SC_BAD_ATTRIBUTES = 0x180, + NVME_SC_INVALID_PI = 0x181, + NVME_SC_READ_ONLY = 0x182, + NVME_SC_ONCS_NOT_SUPPORTED = 0x183, + + /* + * I/O Command Set Specific - Fabrics commands: + */ + NVME_SC_CONNECT_FORMAT = 0x180, + NVME_SC_CONNECT_CTRL_BUSY = 0x181, + NVME_SC_CONNECT_INVALID_PARAM = 0x182, + NVME_SC_CONNECT_RESTART_DISC = 0x183, + NVME_SC_CONNECT_INVALID_HOST = 0x184, + + NVME_SC_DISCOVERY_RESTART = 0x190, + NVME_SC_AUTH_REQUIRED = 0x191, + + /* + * Media and Data Integrity Errors: + */ + NVME_SC_WRITE_FAULT = 0x280, + NVME_SC_READ_ERROR = 0x281, + NVME_SC_GUARD_CHECK = 0x282, + NVME_SC_APPTAG_CHECK = 0x283, + NVME_SC_REFTAG_CHECK = 0x284, + NVME_SC_COMPARE_FAILED = 0x285, + NVME_SC_ACCESS_DENIED = 0x286, + NVME_SC_UNWRITTEN_BLOCK = 0x287, + + /* + * Path-related Errors: + */ + NVME_SC_ANA_PERSISTENT_LOSS = 0x301, + NVME_SC_ANA_INACCESSIBLE = 0x302, + NVME_SC_ANA_TRANSITION = 0x303, + + NVME_SC_DNR = 0x4000, +}; + +const gchar *fu_nvme_status_to_string (guint32 status); + +G_END_DECLS + +#endif /* __FU_NVME_COMMON_H */ diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 234f5e01f..f11c7ddf8 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -19,6 +19,7 @@ #include #include "fu-chunk.h" +#include "fu-nvme-common.h" #include "fu-nvme-device.h" #define FU_NVME_ID_CTRL_SIZE 0x1000 @@ -100,7 +101,12 @@ fu_nvme_device_get_guid_safe (const guint8 *buf, guint16 addr_start) static gboolean fu_nvme_device_submit_admin_passthru (FuNvmeDevice *self, struct nvme_admin_cmd *cmd, GError **error) { - if (ioctl (self->fd, NVME_IOCTL_ADMIN_CMD, cmd) < 0) { + gint rc; + guint32 err; + + /* submit admin command */ + rc = ioctl (self->fd, NVME_IOCTL_ADMIN_CMD, cmd); + if (rc < 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, @@ -109,7 +115,26 @@ fu_nvme_device_submit_admin_passthru (FuNvmeDevice *self, struct nvme_admin_cmd strerror (errno)); return FALSE; } - return TRUE; + + /* check the error code */ + err = rc & 0x3ff; + switch (err) { + case NVME_SC_SUCCESS: + /* devices are always added with _NEEDS_REBOOT, so ignore */ + case NVME_SC_FW_NEEDS_CONV_RESET: + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + case NVME_SC_FW_NEEDS_RESET: + return TRUE; + default: + break; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported: %s", + fu_nvme_status_to_string (err)); + return FALSE; + } static gboolean diff --git a/plugins/nvme/meson.build b/plugins/nvme/meson.build index a3af4638b..a46fccbe2 100644 --- a/plugins/nvme/meson.build +++ b/plugins/nvme/meson.build @@ -3,6 +3,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginNvme"'] shared_module('fu_plugin_nvme', sources : [ 'fu-plugin-nvme.c', + 'fu-nvme-common.c', 'fu-nvme-device.c', ], include_directories : [ @@ -32,6 +33,7 @@ if get_option('tests') 'nvme-self-test', sources : [ 'fu-self-test.c', + 'fu-nvme-common.c', 'fu-nvme-device.c', ], include_directories : [ From 78efa4d2a6f0b28ea20ad50594c77481429b63fc Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 15 Jan 2019 08:27:40 -0600 Subject: [PATCH 167/254] trivial: thunderbolt: If unable to find inactive nvmem, don't mark updatable This situation may happen in the future in systems where the TBT NVM is embedded in a different location and only upgradable through system firmware. --- plugins/thunderbolt/fu-plugin-thunderbolt.c | 51 +++++++++++++++------ 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index 43e1e2c42..db18b5516 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -218,6 +218,22 @@ fu_plugin_thunderbolt_is_native (GUdevDevice *udevice, gboolean *is_native, GErr error); } +static gboolean +fu_plugin_thunderbolt_can_update (GUdevDevice *udevice) +{ + g_autoptr(GError) nvmem_error = NULL; + g_autoptr(GFile) non_active_nvmem = NULL; + + non_active_nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, FALSE, + &nvmem_error); + if (non_active_nvmem == NULL) { + g_debug ("%s", nvmem_error->message); + return FALSE; + } + + return TRUE; +} + static void fu_plugin_thunderbolt_add (FuPlugin *plugin, GUdevDevice *device) { @@ -299,22 +315,29 @@ fu_plugin_thunderbolt_add (FuPlugin *plugin, GUdevDevice *device) is_safemode ? "True" : "False"); } if (!is_safemode) { - if (is_host) { - g_autoptr(GError) error_local = NULL; - if (!fu_plugin_thunderbolt_is_native (device, &is_native, &error_local)) { - g_warning ("failed to get native mode status: %s", error_local->message); - return; + if (fu_plugin_thunderbolt_can_update (device)) { + if (is_host) { + g_autoptr(GError) native_error = NULL; + if (!fu_plugin_thunderbolt_is_native (device, + &is_native, + &native_error)) { + g_warning ("failed to get native mode status: %s", + native_error->message); + return; + } + fu_plugin_add_report_metadata (plugin, + "ThunderboltNative", + is_native ? "True" : "False"); } - fu_plugin_add_report_metadata (plugin, - "ThunderboltNative", - is_native ? "True" : "False"); + vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); + device_id = g_strdup_printf ("TBT-%04x%04x%s", + (guint) vid, + (guint) did, + is_native ? "-native" : ""); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_device_set_update_error (dev, "Missing non-active nvmem"); } - vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); - device_id = g_strdup_printf ("TBT-%04x%04x%s", - (guint) vid, - (guint) did, - is_native ? "-native" : ""); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); } else { fu_device_set_update_error (dev, "Device is in safe mode"); } From ed021ab4487f8ac020481bea372f83da06d95b91 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 10 Jan 2019 16:52:59 -0600 Subject: [PATCH 168/254] upower: Add support for checking battery percentage On any devices that normally would require checking for AC also check that at least one battery on the system has at least 30% to perform an update. Fixes: #925 --- plugins/upower/fu-plugin-upower.c | 103 +++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/plugins/upower/fu-plugin-upower.c b/plugins/upower/fu-plugin-upower.c index c68adb007..3b6d7ed3c 100644 --- a/plugins/upower/fu-plugin-upower.c +++ b/plugins/upower/fu-plugin-upower.c @@ -8,8 +8,11 @@ #include "fu-plugin-vfuncs.h" +#define MINIMUM_BATTERY_PERCENTAGE 30 + struct FuPluginData { - GDBusProxy *proxy; + GDBusProxy *upower_proxy; + GDBusProxy *display_proxy; }; void @@ -22,15 +25,17 @@ void fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); - if (data->proxy != NULL) - g_object_unref (data->proxy); + if (data->upower_proxy != NULL) + g_object_unref (data->upower_proxy); + if (data->display_proxy != NULL) + g_object_unref (data->display_proxy); } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - data->proxy = + data->upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL, @@ -39,31 +44,87 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) "org.freedesktop.UPower", NULL, error); - if (data->proxy == NULL) { + if (data->upower_proxy == NULL) { g_prefix_error (error, "failed to connect to upower: "); return FALSE; } + data->display_proxy = + g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "org.freedesktop.UPower", + "/org/freedesktop/UPower/devices/DisplayDevice", + "org.freedesktop.UPower.Device", + NULL, + error); + if (data->display_proxy == NULL) { + g_prefix_error (error, "failed to connect to upower: "); + return FALSE; + } + return TRUE; } +static gboolean +fu_plugin_upower_check_percentage_level (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gdouble level; + guint power_type; + g_autoptr(GVariant) percentage_val = NULL; + g_autoptr(GVariant) type_val = NULL; + + /* check that we "have" a battery */ + type_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Type"); + if (type_val == NULL) { + g_warning ("Failed to query power type, assume AC power"); + return TRUE; + } + power_type = g_variant_get_uint32 (type_val); + if (power_type != 2) { + g_debug ("Not running on battery (Type: %u)", power_type); + return TRUE; + } + + /* check percentage high enough */ + percentage_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Percentage"); + if (percentage_val == NULL) { + g_warning ("Failed to query power percentage level, assume enough charge"); + return TRUE; + } + level = g_variant_get_double (percentage_val); + g_debug ("System power source is %.1f%%", level); + + return level >= MINIMUM_BATTERY_PERCENTAGE; +} + +static gboolean +fu_plugin_upower_check_on_battery (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(GVariant) value = NULL; + + value = g_dbus_proxy_get_cached_property (data->upower_proxy, "OnBattery"); + if (value == NULL) { + g_warning ("failed to get OnBattery value, assume on AC power"); + return TRUE; + } + return g_variant_get_boolean (value); +} + gboolean fu_plugin_update_prepare (FuPlugin *plugin, FwupdInstallFlags flags, FuDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(GVariant) value = NULL; - - /* can we only do this on AC power */ + /* not all devices need this */ if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC)) return TRUE; - value = g_dbus_proxy_get_cached_property (data->proxy, "OnBattery"); - if (value == NULL) { - g_warning ("failed to get OnBattery value, assume on AC power"); - return TRUE; - } - if (g_variant_get_boolean (value) && (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + + /* determine if operating on AC or battery */ + if (fu_plugin_upower_check_on_battery (plugin) && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_AC_POWER_REQUIRED, @@ -71,5 +132,17 @@ fu_plugin_update_prepare (FuPlugin *plugin, "when not on AC power unless forced"); return FALSE; } + + /* deteremine if battery high enough */ + if (!fu_plugin_upower_check_percentage_level (plugin) && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_AC_POWER_REQUIRED, + "Cannot install update when battery " + "is not at least %d%% unless forced", + MINIMUM_BATTERY_PERCENTAGE); + return FALSE; + } return TRUE; } From 4c0df63db1f451114f0608507f05b861705bfcf9 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 15 Jan 2019 14:40:57 -0600 Subject: [PATCH 169/254] trivial: meson.build: Fix builds with -Ddaemon=false but no other changes Without this fix build will fail like below: ``` $ meson build -Ddaemon=false . . . src/meson.build:21:4: ERROR: Unknown variable "colorhug_pkcs7_signature". ``` --- data/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/meson.build b/data/meson.build index 8dd2ac9ad..67e2b0584 100644 --- a/data/meson.build +++ b/data/meson.build @@ -3,8 +3,10 @@ subdir('pki') subdir('remotes.d') subdir('bash-completion') -if get_option('tests') and get_option('daemon') +if get_option('tests') subdir('tests') +endif +if get_option('daemon') subdir('installed-tests') endif From e58fa31887c842986953f2eb0a3584e516bd5372 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 11:21:54 +0000 Subject: [PATCH 170/254] dfu: Fix flashing various Jabra devices Do not unset the quirks when closing the device, the _NO_DFU_RUNTIME quirk is needed when re-opening the device during detach. Fixes https://github.com/hughsie/fwupd/issues/927 --- plugins/dfu/dfu-device.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/dfu/dfu-device.c b/plugins/dfu/dfu-device.c index 33001e17c..9142fcaee 100644 --- a/plugins/dfu/dfu-device.c +++ b/plugins/dfu/dfu-device.c @@ -578,6 +578,7 @@ dfu_device_set_quirks_from_string (DfuDevice *device, const gchar *str) { DfuDevicePrivate *priv = GET_PRIVATE (device); g_auto(GStrv) split = g_strsplit (str, ",", -1); + priv->quirks = DFU_DEVICE_QUIRK_NONE; for (guint i = 0; split[i] != NULL; i++) { if (g_strcmp0 (split[i], "ignore-polltimeout") == 0) { priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT; @@ -1442,9 +1443,6 @@ dfu_device_close (FuUsbDevice *device, GError **error) DfuDevicePrivate *priv = GET_PRIVATE (self); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - /* unset the quirks */ - priv->quirks = DFU_DEVICE_QUIRK_NONE; - /* release interface */ if (priv->claimed_interface) { g_usb_device_release_interface (usb_device, From b6e9dacc9a74b2dbbb3e1108b5a7fefb56c737ad Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 12:25:33 +0000 Subject: [PATCH 171/254] uefi: Do not check the BGRT status before uploading a UX capsule Microsoft description about the Status is: The Status field of the BGRT describes whether the image is currently displayed on the screen. This is not applicable to the firmware update display capsule. Many thanks to Steven Chang for identifying this issue. Fixes: https://github.com/hughsie/fwupd/issues/935 --- plugins/uefi/fu-uefi-bgrt.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/plugins/uefi/fu-uefi-bgrt.c b/plugins/uefi/fu-uefi-bgrt.c index 52d489553..66b2c4f9e 100644 --- a/plugins/uefi/fu-uefi-bgrt.c +++ b/plugins/uefi/fu-uefi-bgrt.c @@ -24,7 +24,6 @@ gboolean fu_uefi_bgrt_setup (FuUefiBgrt *self, GError **error) { gsize sz = 0; - guint64 status; guint64 type; guint64 version; g_autofree gchar *bgrtdir = NULL; @@ -43,14 +42,6 @@ fu_uefi_bgrt_setup (FuUefiBgrt *self, GError **error) "BGRT is not supported"); return FALSE; } - status = fu_uefi_read_file_as_uint64 (bgrtdir, "status"); - if (status != 1) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "BGRT status was %" G_GUINT64_FORMAT, status); - return FALSE; - } type = fu_uefi_read_file_as_uint64 (bgrtdir, "type"); if (type != 0) { g_set_error (error, From 1eaf71c91b317646712797ec1ea7d5437a75dcba Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 09:15:04 +0000 Subject: [PATCH 172/254] nvme: Add trivial comment to clarify address bitshifting --- plugins/nvme/fu-nvme-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index f11c7ddf8..87c996057 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -177,8 +177,8 @@ fu_nvme_device_fw_download (FuNvmeDevice *self, .opcode = 0x11, .addr = 0x0, /* memory address of data */ .data_len = data_sz, - .cdw10 = (data_sz >> 2) - 1, - .cdw11 = addr >> 2, + .cdw10 = (data_sz >> 2) - 1, /* convert to DWORDs */ + .cdw11 = addr >> 2, /* convert to DWORDs */ }; memcpy (&cmd.addr, &data, sizeof (gpointer)); return fu_nvme_device_submit_admin_passthru (self, &cmd, error); From a9d81cfb10353c0299f8e06a39baaefb78f96556 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 15 Jan 2019 20:08:43 +0000 Subject: [PATCH 173/254] nvme: Support FWUG to get the write block size --- plugins/nvme/fu-nvme-device.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 87c996057..e9afcf3d6 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -244,6 +244,7 @@ static gboolean fu_nvme_device_parse_cns (FuNvmeDevice *self, const guint8 *buf, gsize sz, GError **error) { guint8 fawr; + guint8 fwug; guint8 nfws; guint8 s1ro; g_autofree gchar *mn = NULL; @@ -274,6 +275,11 @@ fu_nvme_device_parse_cns (FuNvmeDevice *self, const guint8 *buf, gsize sz, GErro return FALSE; } + /* firmware update granularity (FWUG) */ + fwug = buf[319]; + if (fwug != 0x00 && fwug != 0xff) + self->write_block_size = ((guint64) fwug) * 0x1000; + /* firmware slot information */ fawr = (buf[260] & 0x10) >> 4; nfws = (buf[260] & 0x0e) >> 1; From d5f0da15ab1486b71ae327b96a38b99226dc238b Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 15 Jan 2019 20:09:45 +0000 Subject: [PATCH 174/254] nvme: Support FGUID to get the SKU GUID --- plugins/nvme/README.md | 4 ++++ plugins/nvme/fu-nvme-device.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/plugins/nvme/README.md b/plugins/nvme/README.md index 1247521cc..776166ad8 100644 --- a/plugins/nvme/README.md +++ b/plugins/nvme/README.md @@ -26,6 +26,10 @@ These device use the NVMe DeviceInstanceId values, e.g. * `NVME\VEN_1179&DEV_010F` * `NVME\VEN_1179` +The FRU globally unique identifier (FGUID) is also added from the CNS if set. +Please refer to this document for more details on how to add support for FGUID: +https://nvmexpress.org/wp-content/uploads/NVM_Express_Revision_1.3.pdf + Additionally, for NVMe drives with Dell vendor firmware two extra GUIDs are added: diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index e9afcf3d6..9b05dad5f 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -247,6 +247,7 @@ fu_nvme_device_parse_cns (FuNvmeDevice *self, const guint8 *buf, gsize sz, GErro guint8 fwug; guint8 nfws; guint8 s1ro; + g_autofree gchar *gu = NULL; g_autofree gchar *mn = NULL; g_autofree gchar *sn = NULL; g_autofree gchar *sr = NULL; @@ -286,6 +287,11 @@ fu_nvme_device_parse_cns (FuNvmeDevice *self, const guint8 *buf, gsize sz, GErro s1ro = buf[260] & 0x01; g_debug ("fawr: %u, nr fw slots: %u, slot1 r/o: %u", fawr, nfws, s1ro); + /* FRU globally unique identifier (FGUID) */ + gu = fu_nvme_device_get_guid_safe (buf, 127); + if (gu != NULL) + fu_device_add_guid (FU_DEVICE (self), gu); + /* Dell helpfully provide an EFI GUID we can use in the vendor offset, * but don't have a header or any magic we can use -- so check if the * component ID looks plausible and the GUID is "sane" */ From fc90f3954e25749270a91fd4551b417bfee66b3d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 15 Jan 2019 21:21:16 +0000 Subject: [PATCH 175/254] nvme: Add flag to support manually aligning the firmware to the FWUG value This is required for drives from Phison. --- plugins/nvme/README.md | 1 + plugins/nvme/fu-nvme-device.c | 11 +++++++++- plugins/nvme/meson.build | 6 ++++++ plugins/nvme/nvme.quirk | 3 +++ src/fu-common.c | 38 +++++++++++++++++++++++++++++++++++ src/fu-common.h | 3 +++ 6 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 plugins/nvme/nvme.quirk diff --git a/plugins/nvme/README.md b/plugins/nvme/README.md index 776166ad8..8b6bb2f3f 100644 --- a/plugins/nvme/README.md +++ b/plugins/nvme/README.md @@ -44,3 +44,4 @@ This plugin uses the following plugin-specific quirks: | Quirk | Description | Minimum fwupd version | |------------------------|---------------------------------------------|-----------------------| | `NvmeBlockSize` | The block size used for NVMe writes | 1.1.3 | +| `Flags` | `force-align` if image should be padded | 1.2.4 | diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 9b05dad5f..e6ba61603 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -410,12 +410,21 @@ static gboolean fu_nvme_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) { FuNvmeDevice *self = FU_NVME_DEVICE (device); + g_autoptr(GBytes) fw2 = NULL; g_autoptr(GPtrArray) chunks = NULL; guint64 block_size = self->write_block_size > 0 ? self->write_block_size : 0x1000; + /* some vendors provide firmware files whose sizes are not multiples + * of blksz *and* the device won't accept blocks of different sizes */ + if (fu_device_has_custom_flag (device, "force-align")) { + fw2 = fu_common_bytes_align (fw, block_size, 0xff); + } else { + fw2 = g_bytes_ref (fw); + } + /* build packets */ - chunks = fu_chunk_array_new_from_bytes (fw, + chunks = fu_chunk_array_new_from_bytes (fw2, 0x00, /* start_addr */ 0x00, /* page_sz */ block_size); /* block size */ diff --git a/plugins/nvme/meson.build b/plugins/nvme/meson.build index a46fccbe2..66ecb2878 100644 --- a/plugins/nvme/meson.build +++ b/plugins/nvme/meson.build @@ -1,5 +1,11 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginNvme"'] +install_data([ + 'nvme.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_nvme', sources : [ 'fu-plugin-nvme.c', diff --git a/plugins/nvme/nvme.quirk b/plugins/nvme/nvme.quirk new file mode 100644 index 000000000..72774592d --- /dev/null +++ b/plugins/nvme/nvme.quirk @@ -0,0 +1,3 @@ +# Phison +[DeviceInstanceId=NVME\VEN_1987] +Flags = force-align diff --git a/src/fu-common.c b/src/fu-common.c index d7f55ddaa..893252edc 100644 --- a/src/fu-common.c +++ b/src/fu-common.c @@ -1175,3 +1175,41 @@ fu_common_dump_bytes (const gchar *log_domain, const guint8 *data = g_bytes_get_data (bytes, &len); fu_common_dump_raw (log_domain, title, data, len); } + +/** + * fu_common_bytes_align: + * @bytes: a #GBytes + * @blksz: block size in bytes + * @padval: the byte used to pad the byte buffer + * + * Aligns a block of memory to @blksize using the @padval value; if + * the block is already aligned then the original @bytes is returned. + * + * Returns: (transfer full): a #GBytes, possibly @bytes + * + * Since: 1.2.4 + **/ +GBytes * +fu_common_bytes_align (GBytes *bytes, gsize blksz, gchar padval) +{ + const guint8 *data; + gsize sz; + + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (blksz > 0, NULL); + + /* pad */ + data = g_bytes_get_data (bytes, &sz); + if (sz % blksz != 0) { + gsize sz_align = ((sz / blksz) + 1) * blksz; + guint8 *data_align = g_malloc (sz_align); + memcpy (data_align, data, sz); + memset (data_align + sz, padval, sz_align - sz); + g_debug ("aligning 0x%x bytes to 0x%x", + (guint) sz, (guint) sz_align); + return g_bytes_new_take (data_align, sz_align); + } + + /* perfectly aligned */ + return g_bytes_ref (bytes); +} diff --git a/src/fu-common.h b/src/fu-common.h index 5a2bfcc7e..9c7252195 100644 --- a/src/fu-common.h +++ b/src/fu-common.h @@ -86,6 +86,9 @@ void fu_common_dump_full (const gchar *log_domain, void fu_common_dump_bytes (const gchar *log_domain, const gchar *title, GBytes *bytes); +GBytes *fu_common_bytes_align (GBytes *bytes, + gsize blksz, + gchar padval); typedef guint FuEndianType; From 72c18fd4e457142265f9f68e0a2055e323a88d94 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 15:44:58 +0000 Subject: [PATCH 176/254] Use GCC __cleanup__ features in the EFI loader This simplifies memory management. --- plugins/uefi/efi/fwupdate.c | 101 +++++++++++++++--------------------- 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index ecf621946..aa169b804 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -68,12 +68,32 @@ msleep(unsigned long msecs) }) #endif +/* use GCC __cleanup__ */ +#define _DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ + static inline void name(void *v) \ + { \ + if (*(Type*)v) \ + func (*(Type*)v); \ + } +_DEFINE_CLEANUP_FUNCTION0(void *, _FreePool_p, FreePool) +#define _cleanup_FreePool __attribute__ ((cleanup(_FreePool_p))) + +static inline void * +_steal_pointer(void *pp) +{ + void **ptr = (void **) pp; + void *ref = *ptr; + *ptr = NULL; + return ref; +} + int debug_print(const char *func, const char *file, const int line, CHAR16 *fmt, ...) { va_list args0, args1; - CHAR16 *out0, *out1; + _cleanup_FreePool CHAR16 *out0 = NULL; + _cleanup_FreePool CHAR16 *out1 = NULL; UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; @@ -96,7 +116,6 @@ debug_print(const char *func, const char *file, const int line, if (debugging) Print(L"%s", out0); out1 = PoolPrint(L"%a:%d:%a(): %s", file, line, func, out0); - FreePool(out0); if (!out1) { Print(L"fwupdate: Allocation for debug log failed!\n"); return debugging; @@ -110,8 +129,6 @@ debug_print(const char *func, const char *file, const int line, } set_variable(name, fwupdate_guid, out1, StrSize(out1) - sizeof (CHAR16), attrs); - FreePool(out1); - return debugging; } @@ -249,7 +266,7 @@ read_variable(CHAR16 *name, EFI_GUID guid, void **buf_out, UINTN *buf_size_out, EFI_STATUS rc; UINT32 attributes; UINTN size = 0; - void *buf = NULL; + _cleanup_FreePool void *buf = NULL; rc = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, &attributes, &size, NULL); @@ -273,10 +290,9 @@ read_variable(CHAR16 *name, EFI_GUID guid, void **buf_out, UINTN *buf_size_out, &size, buf); if (EFI_ERROR(rc)) { print(L"Could not get variable \"%s\": %r\n", name, rc); - FreePool(buf); return rc; } - *buf_out = buf; + *buf_out = _steal_pointer(&buf); *buf_size_out = size; *attributes_out = attributes; return EFI_SUCCESS; @@ -366,7 +382,7 @@ static EFI_STATUS find_updates(UINTN *n_updates_out, update_table ***updates_out) { EFI_STATUS rc; - update_table **updates = NULL; + _cleanup_FreePool update_table **updates = NULL; UINTN n_updates = 0; UINTN n_updates_allocated = 128; EFI_STATUS ret = EFI_OUT_OF_RESOURCES; @@ -374,7 +390,7 @@ find_updates(UINTN *n_updates_out, update_table ***updates_out) #define GNVN_BUF_SIZE 1024 UINTN variable_name_allocation = GNVN_BUF_SIZE; UINTN variable_name_size = 0; - CHAR16 *variable_name; + _cleanup_FreePool CHAR16 *variable_name = NULL; EFI_GUID vendor_guid = empty_guid; UINTN mult_res; @@ -398,7 +414,6 @@ find_updates(UINTN *n_updates_out, update_table ***updates_out) if (!variable_name) { print(L"Tried to allocate %d\n", GNVN_BUF_SIZE * 2); print(L"Could not allocate memory.\n"); - FreePool(updates); return EFI_OUT_OF_RESOURCES; } @@ -462,7 +477,7 @@ find_updates(UINTN *n_updates_out, update_table ***updates_out) print(L"Found update %s\n", vn); if (n_updates == n_updates_allocated) { - update_table **new_ups; + update_table **new_ups = NULL; UINTN mul_a, mul_b; if (uintn_mult(n_updates_allocated, 2, &mult_res)) { mul_a = n_updates_allocated; @@ -531,22 +546,16 @@ mult_err: } } - FreePool(variable_name); - *n_updates_out = n_updates; - *updates_out = updates; + *updates_out = _steal_pointer(&updates); return EFI_SUCCESS; err: - FreePool(variable_name); - for (unsigned int i = 0; i < n_updates; i++) { FreePool(updates[i]->name); FreePool(updates[i]->info); FreePool(updates[i]); } - - FreePool(updates); return ret; } @@ -728,8 +737,8 @@ delete_boot_order(CHAR16 *name, EFI_GUID guid) EFI_STATUS rc; UINTN info_size = 0; UINT32 attributes = 0; - void *info_ptr = NULL; - UINT16 *new_info_ptr = NULL; + _cleanup_FreePool void *info_ptr = NULL; + _cleanup_FreePool UINT16 *new_info_ptr = NULL; BOOLEAN num_found = FALSE; UINTN new_list_num = 0; @@ -745,7 +754,6 @@ delete_boot_order(CHAR16 *name, EFI_GUID guid) if (!new_info_ptr) { print(L"Tried to allocate %d\n", info_size); print(L"Could not allocate memory.\n"); - FreePool(info_ptr); return EFI_OUT_OF_RESOURCES; } @@ -760,10 +768,8 @@ delete_boot_order(CHAR16 *name, EFI_GUID guid) } /* if not in the BootOrder list, do not update BootOrder */ - if (!num_found) { - rc = EFI_SUCCESS; - goto out; - } + if (!num_found) + return EFI_SUCCESS; rc = uefi_call_wrapper(RT->SetVariable, 5, L"BootOrder", &guid, attributes, new_list_num * sizeof(UINT16), @@ -771,14 +777,8 @@ delete_boot_order(CHAR16 *name, EFI_GUID guid) if (EFI_ERROR(rc)) { print(L"Could not update variable status for \"%s\": %r\n", name, rc); - goto out; + return rc; } - -out: - - FreePool(info_ptr); - FreePool(new_info_ptr); - return rc; } @@ -789,10 +789,9 @@ delete_boot_entry(void) UINTN variable_name_allocation = GNVN_BUF_SIZE; UINTN variable_name_size = 0; - CHAR16 *variable_name; + _cleanup_FreePool CHAR16 *variable_name = NULL; EFI_GUID vendor_guid = empty_guid; UINTN mult_res; - EFI_STATUS ret = EFI_OUT_OF_RESOURCES; variable_name = AllocateZeroPool(GNVN_BUF_SIZE * 2); if (!variable_name) { @@ -815,16 +814,14 @@ delete_boot_entry(void) if (uintn_mult(new_allocation, 2, &mult_res)) { print(L"%d * 2 would overflow size\n", new_allocation); - ret = EFI_OUT_OF_RESOURCES; - goto err; + return EFI_OUT_OF_RESOURCES; } new_name = AllocatePool(new_allocation * 2); if (!new_name) { print(L"Tried to allocate %d\n", new_allocation * 2); print(L"Could not allocate memory.\n"); - ret = EFI_OUT_OF_RESOURCES; - goto err; + return EFI_OUT_OF_RESOURCES; } CopyMem(new_name, variable_name, variable_name_allocation); @@ -836,8 +833,7 @@ delete_boot_entry(void) break; } else if (EFI_ERROR(rc)) { print(L"Could not get variable name: %r\n", rc); - ret = rc; - goto err; + return rc; } /* check if the variable name is Boot#### */ @@ -846,16 +842,14 @@ delete_boot_entry(void) && vns == 8 && CompareMem(variable_name, L"Boot", 8) == 0) { UINTN info_size = 0; UINT32 attributes = 0; - void *info_ptr = NULL; + _cleanup_FreePool void *info_ptr = NULL; CHAR16 *load_op_description = NULL; CHAR16 target[] = L"Linux Firmware Updater"; rc = read_variable(variable_name, vendor_guid, &info_ptr, &info_size, &attributes); - if (EFI_ERROR(rc)) { - ret = rc; - goto err; - } + if (EFI_ERROR(rc)) + return rc; /* * check if the boot path created by fwupdate, @@ -873,32 +867,21 @@ delete_boot_entry(void) vendor_guid); if (EFI_ERROR(rc)) { print(L"Failed to delete the Linux Firmware Updater boot entry from BootOrder.\n"); - FreePool(info_ptr); - ret = rc; - goto err; + return rc; } rc = delete_variable(variable_name, vendor_guid, attributes); if (EFI_ERROR(rc)) { print(L"Failed to delete the Linux Firmware Updater boot entry.\n"); - FreePool(info_ptr); - ret = rc; - goto err; + return rc; } - - FreePool(info_ptr); break; } - - FreePool(info_ptr); } } - ret = EFI_SUCCESS; -err: - FreePool(variable_name); - return ret; + return EFI_SUCCESS; } static EFI_STATUS From a958e1c32fe22e7589de58213c35a7727a283b68 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 14:49:02 +0000 Subject: [PATCH 177/254] trivial: Fix a potential type-check warning when setting SUPPORTED We can't use the superclassed FuDevice as this was created as a FwupdDevice. --- src/fu-engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 05ebcf756..cde22b289 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2266,7 +2266,7 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) if (remote_id != NULL) { FwupdRelease *rel = fwupd_device_get_release_default (dev); fwupd_release_set_remote_id (rel, remote_id); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED); + fwupd_device_add_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED); } g_ptr_array_add (details, dev); } From b91efa6c38fbbaba39cd12742b5071e2efc4ffb7 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 14:50:27 +0000 Subject: [PATCH 178/254] trivial: Cast to FuDevice from FuUdevDevice --- plugins/udev/fu-plugin-udev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/udev/fu-plugin-udev.c b/plugins/udev/fu-plugin-udev.c index cb3f0ec43..07f64cdf9 100644 --- a/plugins/udev/fu-plugin-udev.c +++ b/plugins/udev/fu-plugin-udev.c @@ -84,8 +84,8 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er return FALSE; /* did we get enough data */ - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_add_icon (device, "audio-card"); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_icon (FU_DEVICE (device), "audio-card"); /* get the FW version from the rom when unlocked */ rom_fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "rom", NULL); From f803964e3746db4125b43450982d81d5bebf702e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 12:22:22 +0000 Subject: [PATCH 179/254] Add _NEEDS_SHUTDOWN flag for devices Some devices require the system to be powered down and back up, rather than just being "warm" rebooted. --- libfwupd/fwupd-enums.c | 4 +++ libfwupd/fwupd-enums.h | 2 ++ src/fu-engine.c | 3 ++- src/fu-plugin.c | 3 ++- src/fu-util.c | 61 ++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/libfwupd/fwupd-enums.c b/libfwupd/fwupd-enums.c index 9154d955a..9041710ca 100644 --- a/libfwupd/fwupd-enums.c +++ b/libfwupd/fwupd-enums.c @@ -139,6 +139,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag) return "registered"; if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_REBOOT) return "needs-reboot"; + if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) + return "needs-shutdown"; if (device_flag == FWUPD_DEVICE_FLAG_REPORTED) return "reported"; if (device_flag == FWUPD_DEVICE_FLAG_NOTIFIED) @@ -193,6 +195,8 @@ fwupd_device_flag_from_string (const gchar *device_flag) return FWUPD_DEVICE_FLAG_REGISTERED; if (g_strcmp0 (device_flag, "needs-reboot") == 0) return FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + if (g_strcmp0 (device_flag, "needs-shutdown") == 0) + return FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; if (g_strcmp0 (device_flag, "reported") == 0) return FWUPD_DEVICE_FLAG_REPORTED; if (g_strcmp0 (device_flag, "notified") == 0) diff --git a/libfwupd/fwupd-enums.h b/libfwupd/fwupd-enums.h index 32f218f7d..7a93c0b06 100644 --- a/libfwupd/fwupd-enums.h +++ b/libfwupd/fwupd-enums.h @@ -83,6 +83,7 @@ typedef enum { * @FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG: The hardware is waiting to be replugged * @FWUPD_DEVICE_FLAG_IGNORE_VALIDATION: Ignore validation safety checks when flashing this device * @FWUPD_DEVICE_FLAG_TRUSTED: Extra metadata can be exposed about this device + * @FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN: Requires system shutdown to apply firmware * * The device flags. **/ @@ -104,6 +105,7 @@ typedef enum { #define FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG (1u << 14) /* Since: 1.1.2 */ #define FWUPD_DEVICE_FLAG_IGNORE_VALIDATION (1u << 15) /* Since: 1.1.2 */ #define FWUPD_DEVICE_FLAG_TRUSTED (1u << 16) /* Since: 1.1.2 */ +#define FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN (1u << 17) /* Since: 1.2.4 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; diff --git a/src/fu-engine.c b/src/fu-engine.c index cde22b289..dfe755e0d 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1651,7 +1651,8 @@ fu_engine_install_blob (FuEngine *self, g_timer_elapsed (timer, NULL)); /* update database */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) { + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) || + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) { fu_device_set_update_state (device, FWUPD_UPDATE_STATE_NEEDS_REBOOT); if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && !fu_history_modify_device (self->history, device, diff --git a/src/fu-plugin.c b/src/fu-plugin.c index 9c4382f4f..882918b83 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -1514,7 +1514,8 @@ fu_plugin_runner_update (FuPlugin *self, } /* no longer valid */ - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) { + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) && + !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) { GPtrArray *checksums = fu_device_get_checksums (device); g_ptr_array_set_size (checksums, 0); } diff --git a/src/fu-util.c b/src/fu-util.c index 20ced0c41..339418808 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -744,6 +744,51 @@ fu_util_update_reboot (GError **error) return val != NULL; } +static gboolean +fu_util_update_shutdown (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + +#ifdef HAVE_SYSTEMD + /* shutdown using logind */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "PowerOff", + g_variant_new ("(b)", TRUE), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#elif defined(HAVE_CONSOLEKIT) + /* shutdown using ConsoleKit */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "Stop", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "No supported backend compiled in to perform the operation."); +#endif + return val != NULL; +} + static gboolean fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -2043,6 +2088,7 @@ static gboolean fu_util_update_all (FuUtilPrivate *priv, GError **error) { gboolean requires_reboot = FALSE; + gboolean requires_shutdown = FALSE; g_autoptr(GPtrArray) devices = NULL; /* get devices from daemon */ @@ -2073,7 +2119,9 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) rel = g_ptr_array_index (rels, 0); if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; - if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + requires_shutdown = TRUE; + else if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) requires_reboot = TRUE; } @@ -2084,7 +2132,16 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) } /* at least one of the updates needed a reboot */ - if (requires_reboot) { + if (requires_shutdown) { + g_print ("\n%s %s [Y|n]: ", + /* TRANSLATORS: explain why we want to upload */ + _("An update requires the system to shutdown to complete."), + /* TRANSLATORS: reboot to apply the update */ + _("Shutdown now?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + return fu_util_update_shutdown (error); + } else if (requires_reboot) { g_print ("\n%s %s [Y|n]: ", /* TRANSLATORS: explain why we want to upload */ _("An update requires a reboot to complete."), From 4a68fd60dc9546856ca19f540a7225545089d4fd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 16 Jan 2019 14:58:56 +0000 Subject: [PATCH 180/254] nvme: Add the needs-shutdown quirk to Phison NVMe drives Affected drives should have a prominent statement in the update description, possibly even the first line so it shows up by default in the updates panel. --- plugins/nvme/fu-nvme-device.c | 6 +++++- plugins/nvme/nvme.quirk | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index e6ba61603..1470f5a1d 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -373,6 +373,11 @@ fu_nvme_device_probe (FuUdevDevice *device, GError **error) if (self->pci_depth <= 2) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + /* all devices need at least a warm reset, but some quirked drives + * need a full "cold" shutdown and startup */ + if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + return TRUE; } @@ -483,7 +488,6 @@ fu_nvme_device_init (FuNvmeDevice *self) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_set_summary (FU_DEVICE (self), "NVM Express Solid State Drive"); fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); } diff --git a/plugins/nvme/nvme.quirk b/plugins/nvme/nvme.quirk index 72774592d..add862356 100644 --- a/plugins/nvme/nvme.quirk +++ b/plugins/nvme/nvme.quirk @@ -1,3 +1,3 @@ # Phison [DeviceInstanceId=NVME\VEN_1987] -Flags = force-align +Flags = force-align,needs-shutdown From 5dc757f6c1855d660bc9880743678583d14da4c0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Jan 2019 16:11:53 +0000 Subject: [PATCH 181/254] wacom-usb: Add two more Intuos tablets These do not need the runtime-version quirk like the others. --- plugins/wacom-usb/wacom-usb.quirk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/wacom-usb/wacom-usb.quirk b/plugins/wacom-usb/wacom-usb.quirk index 33057e78a..59423a0cd 100644 --- a/plugins/wacom-usb/wacom-usb.quirk +++ b/plugins/wacom-usb/wacom-usb.quirk @@ -48,3 +48,11 @@ Flags = use-runtime-version [DeviceInstanceId=USB\VID_056A&PID_0378] Plugin = wacom-usb Flags = use-runtime-version + +# Intuos Pro Small (2nd-gen USB) [PTH-460] +[DeviceInstanceId=USB\VID_056A&PID_0392] +Plugin = wacom-usb + +# Intuos Pro Small (2nd-gen Bluetooth) [PTH-460] +[DeviceInstanceId=USB\VID_056A&PID_0393] +Plugin = wacom-usb From e554c1b501e48f0d3d79f7d7671a2b1fd9e68c46 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Jan 2019 18:13:47 +0000 Subject: [PATCH 182/254] trivial: Clarify our position on proprietary plugins --- plugins/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/README.md b/plugins/README.md index e295facfc..42d83921f 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -11,6 +11,9 @@ If you have a firmware specification and would like to see support in this project, please file an issue and share the spec. Patches are also welcome. +We will not accept plugins that upgrade hardware using a proprietary Linux +executable, library, or DBus interface. + Plugin interaction ------------------ Some plugins may be able to influence the behavior of other plugins. From 4bdb513937c74bcdce1394e6fd925d8b86c7add2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Jan 2019 11:22:54 +0000 Subject: [PATCH 183/254] trivial: Make the capsule_image_size calculation more obvious --- plugins/uefi/fu-plugin-uefi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 708f0afe1..3cf764db6 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -203,7 +203,7 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GBytes *blob, GError **error capsule_header.capsule_image_size = g_bytes_get_size (blob) + sizeof(efi_capsule_header_t) + - sizeof(header); + sizeof(efi_ux_capsule_header_t); memset (&header, '\0', sizeof(header)); header.version = 1; From 09bf3b52468353e9e5e2304b69a377e7aac3cd5e Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Jan 2019 11:23:50 +0000 Subject: [PATCH 184/254] trivial: Don't manually zero-fill efi_ux_capsule_header_t --- plugins/uefi/fu-plugin-uefi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 3cf764db6..2738d9f8d 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -166,7 +166,7 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GBytes *blob, GError **error gsize buf_size = g_bytes_get_size (blob); gssize size; guint32 height, width; - efi_ux_capsule_header_t header; + efi_ux_capsule_header_t header = { 0 }; efi_capsule_header_t capsule_header = { .flags = EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET, .guid = efi_guid_ux_capsule, @@ -205,7 +205,6 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GBytes *blob, GError **error sizeof(efi_capsule_header_t) + sizeof(efi_ux_capsule_header_t); - memset (&header, '\0', sizeof(header)); header.version = 1; header.image_type = 0; header.reserved = 0; From 4e30d2566860e2ff53dbad34008d60537d8508b8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Jan 2019 11:31:20 +0000 Subject: [PATCH 185/254] UEFI: Do the UX checksum calculation in fwupd This makes the EFI binary much simpler. --- plugins/uefi/efi/fwupdate.c | 56 ----------------- plugins/uefi/efi/hexdump.h | 111 ---------------------------------- plugins/uefi/fu-plugin-uefi.c | 19 ++++++ 3 files changed, 19 insertions(+), 167 deletions(-) delete mode 100644 plugins/uefi/efi/hexdump.h diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index aa169b804..e4796d1ed 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -10,7 +10,6 @@ #include #include "fwup-efi.h" -#include "hexdump.h" #define UNUSED __attribute__((__unused__)) @@ -921,34 +920,12 @@ get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) return EFI_UNSUPPORTED; } -static UINT32 csum(UINT8 *buf, UINTN size) -{ - UINT32 sum = 0; - UINTN i; - - dprint(L"checksumming %d bytes at 0x%08x\n", size, buf); - - for (i = 0; i < size; i++) { - sum += buf[i]; - if (debugging) - Print(L"\rpos:%08lx csum:%d", buf+i, sum); - } - if (debugging) - Print(L"\n"); - - return sum; -} - static EFI_STATUS do_ux_csum(EFI_HANDLE loaded_image, UINT8 *buf, UINTN size) { ux_capsule_header_t *payload_hdr; EFI_CAPSULE_HEADER *capsule; EFI_STATUS rc; - UINTN sum = 0; - - UINT8 *current = buf; - UINTN left = size; if (size < sizeof(*capsule)) { dprint(L"Invalid capsule size %d\n", size); @@ -956,44 +933,11 @@ do_ux_csum(EFI_HANDLE loaded_image, UINT8 *buf, UINTN size) } capsule = (EFI_CAPSULE_HEADER *)buf; - - if (debugging) - hexdump(buf, size <= 0x40 ? size : 0x40); - - dprint(L"size: %d\n", size); - dprint(L"&HeaderSize: 0x%08lx\n", &capsule->HeaderSize); - dprint(L"HeaderSize: %d\n", capsule->HeaderSize); - dprint(L"&CapsuleImageSize: 0x%08lx\n", &capsule->CapsuleImageSize); - dprint(L"CapsuleImageSize: %d\n", capsule->CapsuleImageSize); - - if (size < capsule->HeaderSize) { - dprint(L"Invalid capsule header size %d\n", size); - return EFI_INVALID_PARAMETER; - } - - sum += csum(current, capsule->HeaderSize); - current += capsule->HeaderSize; - left -= capsule->HeaderSize; - payload_hdr = (ux_capsule_header_t *)(buf) + capsule->HeaderSize; - dprint(L"&PayloadHeader: 0x%08lx\n", payload_hdr); - dprint(L"PayloadHeader Size: %d\n", sizeof (*payload_hdr)); rc = get_gop_mode(&payload_hdr->mode, loaded_image); if (EFI_ERROR(rc)) return EFI_UNSUPPORTED; - payload_hdr->checksum = 0; - sum += csum(current, sizeof(*payload_hdr)); - current += sizeof(*payload_hdr); - left -= sizeof(*payload_hdr); - - sum += csum(current, left); - dprint(L"sum is 0x%02hhx; setting ->checksum to 0x%02hhx\n", - sum & 0xff, (uint8_t)((int8_t)(0 - (sum & 0xff)))); - - payload_hdr->checksum = (uint8_t)((int8_t)(0 - sum)); - dprint(L"checksum is set...\n"); - return EFI_SUCCESS; } diff --git a/plugins/uefi/efi/hexdump.h b/plugins/uefi/efi/hexdump.h deleted file mode 100644 index 7a96b3851..000000000 --- a/plugins/uefi/efi/hexdump.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2015-2016 Peter Jones - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef STATIC_HEXDUMP_H -#define STATIC_HEXDUMP_H - -static int -__attribute__((__unused__)) -isprint(char c) -{ - if (c < 0x20) - return 0; - if (c > 0x7e) - return 0; - return 1; -} - -static UINTN -__attribute__((__unused__)) -format_hex(UINT8 *data, UINTN size, CHAR16 *buf) -{ - UINTN sz = (UINTN)data % 16; - CHAR16 hexchars[] = L"0123456789abcdef"; - int offset = 0; - unsigned int i; - unsigned int j; - - for (i = 0; i < sz; i++) { - buf[offset++] = L' '; - buf[offset++] = L' '; - buf[offset++] = L' '; - if (i == 7) - buf[offset++] = L' '; - } - for (j = sz; j < 16 && j < size; j++) { - UINT8 d = data[j-sz]; - buf[offset++] = hexchars[(d & 0xf0) >> 4]; - buf[offset++] = hexchars[(d & 0x0f)]; - if (j != 15) - buf[offset++] = L' '; - if (j == 7) - buf[offset++] = L' '; - } - for (i = j; i < 16; i++) { - buf[offset++] = L' '; - buf[offset++] = L' '; - if (i != 15) - buf[offset++] = L' '; - if (i == 7) - buf[offset++] = L' '; - } - buf[offset] = L'\0'; - return j - sz; -} - -static void -__attribute__((__unused__)) -format_text(UINT8 *data, UINTN size, CHAR16 *buf) -{ - UINTN sz = (UINTN)data % 16; - int offset = 0; - unsigned int i; - unsigned int j; - - for (i = 0; i < sz; i++) - buf[offset++] = L' '; - buf[offset++] = L'|'; - for (j = sz; j < 16 && j < size; j++) { - if (isprint(data[j-sz])) - buf[offset++] = data[j-sz]; - else - buf[offset++] = L'.'; - } - buf[offset++] = L'|'; - for (i = j; i < 16; i++) - buf[offset++] = L' '; - buf[offset] = L'\0'; -} - -static void -__attribute__((__unused__)) -hexdump(UINT8 *data, UINTN size) -{ - UINTN display_offset = (UINTN)data & 0xffffffff; - UINTN offset = 0; - //Print(L"hexdump: data=0x%016x size=0x%x\n", data, size); - - while (offset < size) { - CHAR16 hexbuf[49]; - CHAR16 txtbuf[19]; - UINTN sz; - - sz = format_hex(data+offset, size-offset, hexbuf); - if (sz == 0) - return; - uefi_call_wrapper(BS->Stall, 1, 200000); - - format_text(data+offset, size-offset, txtbuf); - Print(L"%08x %s %s\n", display_offset, hexbuf, txtbuf); - uefi_call_wrapper(BS->Stall, 1, 200000); - - display_offset += sz; - offset += sz; - } -} - - -#endif diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 2738d9f8d..9c7d37f48 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -158,6 +158,15 @@ fu_plugin_uefi_get_splash_data (guint width, guint height, GError **error) return g_bytes_new_take (g_steal_pointer (&buf), buf_idx); } +static guint8 +fu_plugin_uefi_calc_checksum (const guint8 *buf, gsize sz) +{ + guint8 csum = 0; + for (gsize i = 0; i < sz; i++) + csum += buf[i]; + return csum; +} + static gboolean fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GBytes *blob, GError **error) { @@ -166,6 +175,7 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GBytes *blob, GError **error gsize buf_size = g_bytes_get_size (blob); gssize size; guint32 height, width; + guint8 csum = 0; efi_ux_capsule_header_t header = { 0 }; efi_capsule_header_t capsule_header = { .flags = EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET, @@ -212,6 +222,15 @@ fu_plugin_uefi_write_splash_data (FuPlugin *plugin, GBytes *blob, GError **error header.y_offset = fu_uefi_bgrt_get_yoffset (data->bgrt) + fu_uefi_bgrt_get_height (data->bgrt); + /* header, payload and image has to add to zero */ + csum += fu_plugin_uefi_calc_checksum ((guint8 *) &capsule_header, + sizeof(capsule_header)); + csum += fu_plugin_uefi_calc_checksum ((guint8 *) &header, + sizeof(header)); + csum += fu_plugin_uefi_calc_checksum (g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + header.checksum = 0x100 - csum; + /* write capsule file */ size = g_output_stream_write (ostream, &capsule_header, capsule_header.header_size, NULL, error); From f425d29a281b27b8989d337b0e77de67bf4e1a11 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Jan 2019 17:57:39 +0000 Subject: [PATCH 186/254] Show a console warning if loading an out-of-tree plugin Fixes https://github.com/hughsie/fwupd/issues/950 --- libfwupd/fwupd-client.c | 46 +++++++++++++++++++ libfwupd/fwupd-client.h | 1 + libfwupd/fwupd.map | 6 +++ meson.build | 3 +- plugins/altos/fu-plugin-altos.c | 1 + plugins/altos/meson.build | 1 + plugins/amt/fu-plugin-amt.c | 6 +++ plugins/amt/meson.build | 1 + plugins/colorhug/fu-plugin-colorhug.c | 1 + plugins/colorhug/meson.build | 1 + plugins/csr/fu-plugin-csr.c | 1 + plugins/csr/meson.build | 1 + plugins/dell-dock/fu-plugin-dell-dock.c | 5 +- plugins/dell-dock/meson.build | 1 + plugins/dell-esrt/fu-plugin-dell-esrt.c | 6 +++ plugins/dell-esrt/meson.build | 1 + plugins/dell/fu-plugin-dell.c | 1 + plugins/dell/meson.build | 1 + plugins/dfu/fu-plugin-dfu.c | 1 + plugins/dfu/meson.build | 2 + plugins/ebitdo/fu-plugin-ebitdo.c | 1 + plugins/ebitdo/meson.build | 1 + plugins/fastboot/fu-plugin-fastboot.c | 1 + plugins/fastboot/meson.build | 1 + plugins/flashrom/fu-plugin-flashrom.c | 1 + plugins/flashrom/meson.build | 1 + plugins/nitrokey/fu-plugin-nitrokey.c | 1 + plugins/nitrokey/meson.build | 1 + plugins/nvme/fu-plugin-nvme.c | 1 + plugins/nvme/meson.build | 1 + plugins/redfish/fu-plugin-redfish.c | 1 + plugins/redfish/meson.build | 1 + plugins/rts54hid/fu-plugin-rts54hid.c | 1 + plugins/rts54hid/meson.build | 1 + plugins/rts54hub/fu-plugin-rts54hub.c | 1 + plugins/rts54hub/meson.build | 1 + plugins/steelseries/fu-plugin-steelseries.c | 1 + plugins/steelseries/meson.build | 1 + plugins/superio/fu-plugin-superio.c | 6 +++ plugins/superio/meson.build | 1 + plugins/synapticsmst/fu-plugin-synapticsmst.c | 1 + plugins/synapticsmst/meson.build | 1 + plugins/test/fu-plugin-test.c | 4 ++ plugins/test/meson.build | 1 + .../fu-plugin-thunderbolt-power.c | 1 + plugins/thunderbolt-power/meson.build | 1 + plugins/thunderbolt/fu-plugin-thunderbolt.c | 1 + plugins/thunderbolt/meson.build | 1 + plugins/udev/fu-plugin-udev.c | 1 + plugins/udev/meson.build | 2 + plugins/uefi/fu-plugin-uefi.c | 1 + plugins/uefi/meson.build | 2 + plugins/unifying/fu-plugin-unifying.c | 1 + plugins/unifying/meson.build | 1 + plugins/upower/fu-plugin-upower.c | 1 + plugins/upower/meson.build | 1 + plugins/wacom-usb/fu-plugin-wacom-usb.c | 1 + plugins/wacom-usb/meson.build | 1 + src/fu-engine.c | 24 +++++++++- src/fu-engine.h | 1 + src/fu-hash.py | 33 +++++++++++++ src/fu-main.c | 3 ++ src/fu-plugin-private.h | 1 + src/fu-plugin-vfuncs.h | 1 + src/fu-plugin.c | 29 ++++++++++++ src/fu-plugin.h | 2 + src/fu-self-test.c | 31 +++++++++++++ src/fu-tool.c | 8 +++- src/fu-util.c | 11 +++++ src/meson.build | 12 +++++ src/org.freedesktop.fwupd.xml | 11 +++++ 71 files changed, 296 insertions(+), 6 deletions(-) create mode 100644 src/fu-hash.py diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 311b6f6b1..649c979c8 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -37,6 +37,7 @@ static void fwupd_client_finalize (GObject *object); typedef struct { FwupdStatus status; + gboolean tainted; guint percentage; gchar *daemon_version; GDBusConnection *conn; @@ -57,6 +58,7 @@ enum { PROP_STATUS, PROP_PERCENTAGE, PROP_DAEMON_VERSION, + PROP_TAINTED, PROP_LAST }; @@ -131,6 +133,14 @@ fwupd_client_properties_changed_cb (GDBusProxy *proxy, g_object_notify (G_OBJECT (client), "status"); } } + if (g_variant_dict_contains (dict, "Tainted")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "Tainted"); + if (val != NULL) { + priv->tainted = g_variant_get_boolean (val); + g_object_notify (G_OBJECT (client), "tainted"); + } + } if (g_variant_dict_contains (dict, "Percentage")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Percentage"); @@ -203,6 +213,7 @@ fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **e { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(GVariant) val = NULL; + g_autoptr(GVariant) val2 = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); @@ -235,6 +246,9 @@ fwupd_client_connect (FwupdClient *client, GCancellable *cancellable, GError **e val = g_dbus_proxy_get_cached_property (priv->proxy, "DaemonVersion"); if (val != NULL) fwupd_client_set_daemon_version (client, g_variant_get_string (val, NULL)); + val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Tainted"); + if (val2 != NULL) + priv->tainted = g_variant_get_boolean (val2); return TRUE; } @@ -1138,6 +1152,24 @@ fwupd_client_get_status (FwupdClient *client) return priv->status; } +/** + * fwupd_client_get_tainted: + * @client: A #FwupdClient + * + * Gets if the daemon has been tainted by 3rd party code. + * + * Returns: %TRUE if the daemon is unsupported + * + * Since: 1.2.4 + **/ +gboolean +fwupd_client_get_tainted (FwupdClient *client) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + return priv->tainted; +} + /** * fwupd_client_update_metadata: * @client: A #FwupdClient @@ -1461,6 +1493,9 @@ fwupd_client_get_property (GObject *object, guint prop_id, case PROP_STATUS: g_value_set_uint (value, priv->status); break; + case PROP_TAINTED: + g_value_set_boolean (value, priv->tainted); + break; case PROP_PERCENTAGE: g_value_set_uint (value, priv->percentage); break; @@ -1598,6 +1633,17 @@ fwupd_client_class_init (FwupdClientClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_STATUS, pspec); + /** + * FwupdClient:tainted: + * + * If the daemon is tainted by 3rd party code. + * + * Since: 1.2.4 + */ + pspec = g_param_spec_boolean ("tainted", NULL, NULL, FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_TAINTED, pspec); + /** * FwupdClient:percentage: * diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index f33011faf..29bc13d54 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -116,6 +116,7 @@ gboolean fwupd_client_modify_device (FwupdClient *client, GCancellable *cancellable, GError **error); FwupdStatus fwupd_client_get_status (FwupdClient *client); +gboolean fwupd_client_get_tainted (FwupdClient *client); guint fwupd_client_get_percentage (FwupdClient *client); const gchar *fwupd_client_get_daemon_version (FwupdClient *client); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 929764fbd..3bedb8cb7 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -293,3 +293,9 @@ LIBFWUPD_1.2.2 { fwupd_release_set_protocol; local: *; } LIBFWUPD_1.2.1; + +LIBFWUPD_1.2.4 { + global: + fwupd_client_get_tainted; + local: *; +} LIBFWUPD_1.2.2; diff --git a/meson.build b/meson.build index b95d7b042..aea7a545b 100644 --- a/meson.build +++ b/meson.build @@ -193,6 +193,7 @@ if libgcab.version().version_compare('>= 1.0') endif gcab = find_program('gcab', required : true) bashcomp = dependency('bash-completion', required: false) +python3 = find_program('python3') if valgrind.found() conf.set('HAVE_VALGRIND', '1') @@ -237,8 +238,6 @@ if get_option('plugin_uefi') gnu_efi_arch = '' endif conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME) - - python3 = find_program('python3') r = run_command([python3, 'po/test-deps']) if r.returncode() != 0 error(r.stdout()) diff --git a/plugins/altos/fu-plugin-altos.c b/plugins/altos/fu-plugin-altos.c index 8cfdc3bd6..9ddcd460e 100644 --- a/plugins/altos/fu-plugin-altos.c +++ b/plugins/altos/fu-plugin-altos.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.altusmetrum.altos"); } diff --git a/plugins/altos/meson.build b/plugins/altos/meson.build index bd0d8e47c..55cb3d841 100644 --- a/plugins/altos/meson.build +++ b/plugins/altos/meson.build @@ -5,6 +5,7 @@ install_data(['altos.quirk'], ) shared_module('fu_plugin_altos', + fu_hash, sources : [ 'fu-altos-device.c', 'fu-altos-firmware.c', diff --git a/plugins/amt/fu-plugin-amt.c b/plugins/amt/fu-plugin-amt.c index ff5ea0e96..44bdf85be 100644 --- a/plugins/amt/fu-plugin-amt.c +++ b/plugins/amt/fu-plugin-amt.c @@ -539,6 +539,12 @@ fu_plugin_amt_create_device (GError **error) return g_steal_pointer (&dev); } +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { diff --git a/plugins/amt/meson.build b/plugins/amt/meson.build index 18ddedb35..0904a2ace 100644 --- a/plugins/amt/meson.build +++ b/plugins/amt/meson.build @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginAmt"'] shared_module('fu_plugin_amt', + fu_hash, sources : [ 'fu-plugin-amt.c', ], diff --git a/plugins/colorhug/fu-plugin-colorhug.c b/plugins/colorhug/fu-plugin-colorhug.c index 1fc356627..9aefa6233 100644 --- a/plugins/colorhug/fu-plugin-colorhug.c +++ b/plugins/colorhug/fu-plugin-colorhug.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.hughski.colorhug"); } diff --git a/plugins/colorhug/meson.build b/plugins/colorhug/meson.build index 3b6b86279..4894f2954 100644 --- a/plugins/colorhug/meson.build +++ b/plugins/colorhug/meson.build @@ -7,6 +7,7 @@ install_data([ ) shared_module('fu_plugin_colorhug', + fu_hash, sources : [ 'fu-colorhug-common.c', 'fu-colorhug-device.c', diff --git a/plugins/csr/fu-plugin-csr.c b/plugins/csr/fu-plugin-csr.c index aaedbbca2..c6e14cea4 100644 --- a/plugins/csr/fu-plugin-csr.c +++ b/plugins/csr/fu-plugin-csr.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.qualcomm.dfu"); } diff --git a/plugins/csr/meson.build b/plugins/csr/meson.build index 3748c18e3..09595c860 100644 --- a/plugins/csr/meson.build +++ b/plugins/csr/meson.build @@ -5,6 +5,7 @@ install_data(['csr-aiaiai.quirk'], ) shared_module('fu_plugin_csr', + fu_hash, sources : [ 'fu-csr-device.c', 'fu-plugin-csr.c', diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index eca46ed57..6992add1a 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -21,8 +21,11 @@ #include "fu-dell-dock-common.h" -void fu_plugin_init (FuPlugin *plugin) +void +fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + /* allow these to be built by quirks */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); g_type_ensure (FU_TYPE_DELL_DOCK_STATUS); diff --git a/plugins/dell-dock/meson.build b/plugins/dell-dock/meson.build index a03a60760..9e719680a 100644 --- a/plugins/dell-dock/meson.build +++ b/plugins/dell-dock/meson.build @@ -5,6 +5,7 @@ install_data(['dell-dock.quirk'], ) shared_module('fu_plugin_dell_dock', + fu_hash, sources : [ 'fu-plugin-dell-dock.c', 'fu-dell-dock-common.c', diff --git a/plugins/dell-esrt/fu-plugin-dell-esrt.c b/plugins/dell-esrt/fu-plugin-dell-esrt.c index 7e32b4f59..a13d78c70 100644 --- a/plugins/dell-esrt/fu-plugin-dell-esrt.c +++ b/plugins/dell-esrt/fu-plugin-dell-esrt.c @@ -83,6 +83,12 @@ fu_plugin_dell_esrt_admin_password_present (gboolean *password_present, GError * return TRUE; } +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { diff --git a/plugins/dell-esrt/meson.build b/plugins/dell-esrt/meson.build index 39fae22d3..45af43ee3 100644 --- a/plugins/dell-esrt/meson.build +++ b/plugins/dell-esrt/meson.build @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginDellEsrt"'] shared_module('fu_plugin_dell_esrt', + fu_hash, sources : [ 'fu-plugin-dell-esrt.c', ], diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index b7bd83f57..42cff459c 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -786,6 +786,7 @@ fu_plugin_init (FuPlugin *plugin) FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); g_autofree gchar *tmp = NULL; + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); tmp = g_strdup_printf ("%d.%d", smbios_get_library_version_major(), smbios_get_library_version_minor()); diff --git a/plugins/dell/meson.build b/plugins/dell/meson.build index 67683591b..df96b979f 100644 --- a/plugins/dell/meson.build +++ b/plugins/dell/meson.build @@ -5,6 +5,7 @@ install_data(['dell.quirk'], ) shared_module('fu_plugin_dell', + fu_hash, sources : [ 'fu-plugin-dell.c', 'fu-dell-smi.c', diff --git a/plugins/dfu/fu-plugin-dfu.c b/plugins/dfu/fu-plugin-dfu.c index 18060a7c4..4b0682edc 100644 --- a/plugins/dfu/fu-plugin-dfu.c +++ b/plugins/dfu/fu-plugin-dfu.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.usb.dfu"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.st.dfuse"); diff --git a/plugins/dfu/meson.build b/plugins/dfu/meson.build index 404b7bbb7..f9d9632dc 100644 --- a/plugins/dfu/meson.build +++ b/plugins/dfu/meson.build @@ -43,6 +43,7 @@ dfu = static_library( ) shared_module('fu_plugin_dfu', + fu_hash, sources : [ 'fu-plugin-dfu.c', ], @@ -65,6 +66,7 @@ shared_module('fu_plugin_dfu', dfu_tool = executable( 'dfu-tool', + fu_hash, sources : [ 'dfu-tool.c', ], diff --git a/plugins/ebitdo/fu-plugin-ebitdo.c b/plugins/ebitdo/fu-plugin-ebitdo.c index 60a6581e0..12b6691b1 100644 --- a/plugins/ebitdo/fu-plugin-ebitdo.c +++ b/plugins/ebitdo/fu-plugin-ebitdo.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.8bitdo"); } diff --git a/plugins/ebitdo/meson.build b/plugins/ebitdo/meson.build index 4d438a740..99c507581 100644 --- a/plugins/ebitdo/meson.build +++ b/plugins/ebitdo/meson.build @@ -5,6 +5,7 @@ install_data(['ebitdo.quirk'], ) shared_module('fu_plugin_ebitdo', + fu_hash, sources : [ 'fu-plugin-ebitdo.c', 'fu-ebitdo-common.c', diff --git a/plugins/fastboot/fu-plugin-fastboot.c b/plugins/fastboot/fu-plugin-fastboot.c index b2ad4023f..0d372fc08 100644 --- a/plugins/fastboot/fu-plugin-fastboot.c +++ b/plugins/fastboot/fu-plugin-fastboot.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.google.fastboot"); } diff --git a/plugins/fastboot/meson.build b/plugins/fastboot/meson.build index 3afa16734..09d9b2323 100644 --- a/plugins/fastboot/meson.build +++ b/plugins/fastboot/meson.build @@ -5,6 +5,7 @@ install_data(['fastboot.quirk'], ) shared_module('fu_plugin_fastboot', + fu_hash, sources : [ 'fu-plugin-fastboot.c', 'fu-fastboot-device.c', diff --git a/plugins/flashrom/fu-plugin-flashrom.c b/plugins/flashrom/fu-plugin-flashrom.c index 11866d059..9085ffe50 100644 --- a/plugins/flashrom/fu-plugin-flashrom.c +++ b/plugins/flashrom/fu-plugin-flashrom.c @@ -32,6 +32,7 @@ struct FuPluginData { void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.flashrom"); } diff --git a/plugins/flashrom/meson.build b/plugins/flashrom/meson.build index ee048e51f..222b5f88f 100644 --- a/plugins/flashrom/meson.build +++ b/plugins/flashrom/meson.build @@ -5,6 +5,7 @@ install_data(['flashrom.quirk'], ) shared_module('fu_plugin_flashrom', + fu_hash, sources : [ 'fu-plugin-flashrom.c', ], diff --git a/plugins/nitrokey/fu-plugin-nitrokey.c b/plugins/nitrokey/fu-plugin-nitrokey.c index 9c4e23609..4061ee7d7 100644 --- a/plugins/nitrokey/fu-plugin-nitrokey.c +++ b/plugins/nitrokey/fu-plugin-nitrokey.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); } diff --git a/plugins/nitrokey/meson.build b/plugins/nitrokey/meson.build index 1aee68859..469114985 100644 --- a/plugins/nitrokey/meson.build +++ b/plugins/nitrokey/meson.build @@ -5,6 +5,7 @@ install_data(['nitrokey.quirk'], ) shared_module('fu_plugin_nitrokey', + fu_hash, sources : [ 'fu-nitrokey-device.c', 'fu-nitrokey-common.c', diff --git a/plugins/nvme/fu-plugin-nvme.c b/plugins/nvme/fu-plugin-nvme.c index b1f89d7ce..25ef68f9f 100644 --- a/plugins/nvme/fu-plugin-nvme.c +++ b/plugins/nvme/fu-plugin-nvme.c @@ -31,6 +31,7 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "nvme"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.nvmexpress"); } diff --git a/plugins/nvme/meson.build b/plugins/nvme/meson.build index 66ecb2878..614ccc609 100644 --- a/plugins/nvme/meson.build +++ b/plugins/nvme/meson.build @@ -7,6 +7,7 @@ install_data([ ) shared_module('fu_plugin_nvme', + fu_hash, sources : [ 'fu-plugin-nvme.c', 'fu-nvme-common.c', diff --git a/plugins/redfish/fu-plugin-redfish.c b/plugins/redfish/fu-plugin-redfish.c index 918801acd..60ca60ece 100644 --- a/plugins/redfish/fu-plugin-redfish.c +++ b/plugins/redfish/fu-plugin-redfish.c @@ -118,6 +118,7 @@ fu_plugin_init (FuPlugin *plugin) FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); data->client = fu_redfish_client_new (); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.dmtf.redfish"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void diff --git a/plugins/redfish/meson.build b/plugins/redfish/meson.build index ef07bd819..a4cdba558 100644 --- a/plugins/redfish/meson.build +++ b/plugins/redfish/meson.build @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginRedfish"'] shared_module('fu_plugin_redfish', + fu_hash, sources : [ 'fu-plugin-redfish.c', 'fu-redfish-client.c', diff --git a/plugins/rts54hid/fu-plugin-rts54hid.c b/plugins/rts54hid/fu-plugin-rts54hid.c index 00621399d..af6699567 100644 --- a/plugins/rts54hid/fu-plugin-rts54hid.c +++ b/plugins/rts54hid/fu-plugin-rts54hid.c @@ -14,6 +14,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); diff --git a/plugins/rts54hid/meson.build b/plugins/rts54hid/meson.build index ff6c621de..809a11349 100644 --- a/plugins/rts54hid/meson.build +++ b/plugins/rts54hid/meson.build @@ -7,6 +7,7 @@ install_data([ ) shared_module('fu_plugin_rts54hid', + fu_hash, sources : [ 'fu-rts54hid-device.c', 'fu-rts54hid-module.c', diff --git a/plugins/rts54hub/fu-plugin-rts54hub.c b/plugins/rts54hub/fu-plugin-rts54hub.c index d0c7eb294..7300f2d1d 100644 --- a/plugins/rts54hub/fu-plugin-rts54hub.c +++ b/plugins/rts54hub/fu-plugin-rts54hub.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); } diff --git a/plugins/rts54hub/meson.build b/plugins/rts54hub/meson.build index 3f525b4ad..46b220382 100644 --- a/plugins/rts54hub/meson.build +++ b/plugins/rts54hub/meson.build @@ -7,6 +7,7 @@ install_data([ ) shared_module('fu_plugin_rts54hub', + fu_hash, sources : [ 'fu-rts54hub-device.c', 'fu-plugin-rts54hub.c', diff --git a/plugins/steelseries/fu-plugin-steelseries.c b/plugins/steelseries/fu-plugin-steelseries.c index f5479c47a..78395cf48 100644 --- a/plugins/steelseries/fu-plugin-steelseries.c +++ b/plugins/steelseries/fu-plugin-steelseries.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); } diff --git a/plugins/steelseries/meson.build b/plugins/steelseries/meson.build index e2fc45ea5..68fe15abc 100644 --- a/plugins/steelseries/meson.build +++ b/plugins/steelseries/meson.build @@ -5,6 +5,7 @@ install_data(['steelseries.quirk'], ) shared_module('fu_plugin_steelseries', + fu_hash, sources : [ 'fu-plugin-steelseries.c', 'fu-steelseries-device.c', diff --git a/plugins/superio/fu-plugin-superio.c b/plugins/superio/fu-plugin-superio.c index 2135cd551..a8f1ed24e 100644 --- a/plugins/superio/fu-plugin-superio.c +++ b/plugins/superio/fu-plugin-superio.c @@ -62,6 +62,12 @@ fu_plugin_superio_coldplug_chipsets (FuPlugin *plugin, const gchar *str, GError return TRUE; } +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { diff --git a/plugins/superio/meson.build b/plugins/superio/meson.build index ecbfad547..06b094342 100644 --- a/plugins/superio/meson.build +++ b/plugins/superio/meson.build @@ -5,6 +5,7 @@ install_data(['superio.quirk'], ) shared_module('fu_plugin_superio', + fu_hash, sources : [ 'fu-plugin-superio.c', 'fu-superio-device.c', diff --git a/plugins/synapticsmst/fu-plugin-synapticsmst.c b/plugins/synapticsmst/fu-plugin-synapticsmst.c index 1ceb540d4..fa86b2144 100644 --- a/plugins/synapticsmst/fu-plugin-synapticsmst.c +++ b/plugins/synapticsmst/fu-plugin-synapticsmst.c @@ -472,4 +472,5 @@ fu_plugin_init (FuPlugin *plugin) /* make sure dell is already coldplugged */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "dell"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } diff --git a/plugins/synapticsmst/meson.build b/plugins/synapticsmst/meson.build index 197620b77..0f1abdbf0 100644 --- a/plugins/synapticsmst/meson.build +++ b/plugins/synapticsmst/meson.build @@ -5,6 +5,7 @@ install_data(['synapticsmst.quirk'], ) shared_module('fu_plugin_synapticsmst', + fu_hash, sources : [ 'fu-plugin-synapticsmst.c', 'synapticsmst-common.c', diff --git a/plugins/test/fu-plugin-test.c b/plugins/test/fu-plugin-test.c index 34023a6d9..9c7875943 100644 --- a/plugins/test/fu-plugin-test.c +++ b/plugins/test/fu-plugin-test.c @@ -15,6 +15,10 @@ struct FuPluginData { void fu_plugin_init (FuPlugin *plugin) { + if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "build-hash") == 0) + fu_plugin_set_build_hash (plugin, "invalid"); + else + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.acme.test"); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); g_debug ("init"); diff --git a/plugins/test/meson.build b/plugins/test/meson.build index 2dfdd91e9..c473ab4b0 100644 --- a/plugins/test/meson.build +++ b/plugins/test/meson.build @@ -6,6 +6,7 @@ if get_option('plugin_dummy') endif shared_module('fu_plugin_test', + fu_hash, sources : [ 'fu-plugin-test.c', ], diff --git a/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c b/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c index 4430347af..4bfc20d01 100644 --- a/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c +++ b/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c @@ -320,6 +320,7 @@ fu_plugin_init (FuPlugin *plugin) /* make sure it's tried to coldplug */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "thunderbolt"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void diff --git a/plugins/thunderbolt-power/meson.build b/plugins/thunderbolt-power/meson.build index 1df672074..747c782f6 100644 --- a/plugins/thunderbolt-power/meson.build +++ b/plugins/thunderbolt-power/meson.build @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] fu_plugin_thunderbolt_power = shared_module('fu_plugin_thunderbolt_power', + fu_hash, sources : [ 'fu-plugin-thunderbolt-power.c', ], diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index db18b5516..3fa0613ce 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -585,6 +585,7 @@ fu_plugin_init (FuPlugin *plugin) FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); const gchar *subsystems[] = { "thunderbolt", NULL }; + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.intel.thunderbolt"); data->udev = g_udev_client_new (subsystems); g_signal_connect (data->udev, "uevent", diff --git a/plugins/thunderbolt/meson.build b/plugins/thunderbolt/meson.build index ce7c76203..10991e5b1 100644 --- a/plugins/thunderbolt/meson.build +++ b/plugins/thunderbolt/meson.build @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] fu_plugin_thunderbolt = shared_module('fu_plugin_thunderbolt', + fu_hash, sources : [ 'fu-plugin-thunderbolt.c', 'fu-thunderbolt-image.c', diff --git a/plugins/udev/fu-plugin-udev.c b/plugins/udev/fu-plugin-udev.c index 07f64cdf9..af48b1add 100644 --- a/plugins/udev/fu-plugin-udev.c +++ b/plugins/udev/fu-plugin-udev.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "pci"); } diff --git a/plugins/udev/meson.build b/plugins/udev/meson.build index 33eb149ca..334b14a87 100644 --- a/plugins/udev/meson.build +++ b/plugins/udev/meson.build @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUdev"'] shared_module('fu_plugin_udev', + fu_hash, sources : [ 'fu-plugin-udev.c', 'fu-rom.c', @@ -23,6 +24,7 @@ shared_module('fu_plugin_udev', executable( 'fu-rom-tool', + fu_hash, sources : [ 'fu-rom-tool.c', 'fu-rom.c', diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 9c7d37f48..26a0b053f 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -40,6 +40,7 @@ fu_plugin_init (FuPlugin *plugin) fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.uefi.capsule"); fu_plugin_add_compile_version (plugin, "com.redhat.efivar", EFIVAR_LIBRARY_VERSION); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void diff --git a/plugins/uefi/meson.build b/plugins/uefi/meson.build index 09ebdf82d..2492e4eca 100644 --- a/plugins/uefi/meson.build +++ b/plugins/uefi/meson.build @@ -8,6 +8,7 @@ install_data(['uefi.quirk'], ) shared_module('fu_plugin_uefi', + fu_hash, sources : [ 'fu-plugin-uefi.c', 'fu-uefi-bgrt.c', @@ -40,6 +41,7 @@ shared_module('fu_plugin_uefi', executable( 'fwupdate', resources_src, + fu_hash, sources : [ 'fu-uefi-tool.c', 'fu-uefi-bgrt.c', diff --git a/plugins/unifying/fu-plugin-unifying.c b/plugins/unifying/fu-plugin-unifying.c index dd9adbcd1..58af46f35 100644 --- a/plugins/unifying/fu-plugin-unifying.c +++ b/plugins/unifying/fu-plugin-unifying.c @@ -173,6 +173,7 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifying"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifyingsigned"); diff --git a/plugins/unifying/meson.build b/plugins/unifying/meson.build index f3ab13008..7e04912db 100644 --- a/plugins/unifying/meson.build +++ b/plugins/unifying/meson.build @@ -8,6 +8,7 @@ install_data([ shared_module('fu_plugin_unifying', + fu_hash, sources : [ 'fu-plugin-unifying.c', 'fu-unifying-bootloader.c', diff --git a/plugins/upower/fu-plugin-upower.c b/plugins/upower/fu-plugin-upower.c index 3b6d7ed3c..780cf34f5 100644 --- a/plugins/upower/fu-plugin-upower.c +++ b/plugins/upower/fu-plugin-upower.c @@ -18,6 +18,7 @@ struct FuPluginData { void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); } diff --git a/plugins/upower/meson.build b/plugins/upower/meson.build index 62c7dfc54..0f9e0dc3a 100644 --- a/plugins/upower/meson.build +++ b/plugins/upower/meson.build @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUpower"'] shared_module('fu_plugin_upower', + fu_hash, sources : [ 'fu-plugin-upower.c', ], diff --git a/plugins/wacom-usb/fu-plugin-wacom-usb.c b/plugins/wacom-usb/fu-plugin-wacom-usb.c index 4617ce482..af82ae425 100644 --- a/plugins/wacom-usb/fu-plugin-wacom-usb.c +++ b/plugins/wacom-usb/fu-plugin-wacom-usb.c @@ -13,6 +13,7 @@ void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.wacom.usb"); } diff --git a/plugins/wacom-usb/meson.build b/plugins/wacom-usb/meson.build index 44374232c..e2a3f37c7 100644 --- a/plugins/wacom-usb/meson.build +++ b/plugins/wacom-usb/meson.build @@ -5,6 +5,7 @@ install_data(['wacom-usb.quirk'], ) shared_module('fu_plugin_wacom_usb', + fu_hash, sources : [ 'fu-wac-common.c', 'fu-wac-device.c', diff --git a/src/fu-engine.c b/src/fu-engine.c index dfe755e0d..8b7c2559a 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -34,6 +34,7 @@ #include "fu-hwids.h" #include "fu-idle.h" #include "fu-keyring-utils.h" +#include "fu-hash.h" #include "fu-history.h" #include "fu-mutex.h" #include "fu-plugin.h" @@ -55,6 +56,7 @@ struct _FuEngine FuConfig *config; FuDeviceList *device_list; FwupdStatus status; + gboolean tainted; guint percentage; FuHistory *history; FuIdle *idle; @@ -3376,10 +3378,22 @@ fu_engine_plugin_set_coldplug_delay_cb (FuPlugin *plugin, guint duration, FuEngi duration, self->coldplug_delay); } -/* for the self tests to use */ +/* this is called by the self tests as well */ void fu_engine_add_plugin (FuEngine *self, FuPlugin *plugin) { + /* plugin does not match built version */ + if (fu_plugin_get_build_hash (plugin) == NULL) { + const gchar *name = fu_plugin_get_name (plugin); + g_warning ("%s should call fu_plugin_set_build_hash()", name); + self->tainted = TRUE; + } else if (g_strcmp0 (fu_plugin_get_build_hash (plugin), FU_BUILD_HASH) != 0) { + const gchar *name = fu_plugin_get_name (plugin); + g_warning ("%s has incorrect built version %s", + name, fu_plugin_get_build_hash (plugin)); + self->tainted = TRUE; + } + fu_plugin_list_add (self->plugin_list, plugin); } @@ -3428,6 +3442,12 @@ fu_engine_plugin_check_supported_cb (FuPlugin *plugin, const gchar *guid, FuEngi return n != NULL; } +gboolean +fu_engine_get_tainted (FuEngine *self) +{ + return self->tainted; +} + gboolean fu_engine_load_plugins (FuEngine *self, GError **error) { @@ -3516,7 +3536,7 @@ fu_engine_load_plugins (FuEngine *self, GError **error) self); /* add */ - fu_plugin_list_add (self->plugin_list, plugin); + fu_engine_add_plugin (self, plugin); } /* depsolve into the correct order */ diff --git a/src/fu-engine.h b/src/fu-engine.h index 67376e652..a15d117d0 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -30,6 +30,7 @@ gboolean fu_engine_load (FuEngine *self, GError **error); gboolean fu_engine_load_plugins (FuEngine *self, GError **error); +gboolean fu_engine_get_tainted (FuEngine *self); FwupdStatus fu_engine_get_status (FuEngine *self); XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, diff --git a/src/fu-hash.py b/src/fu-hash.py new file mode 100644 index 000000000..11cb1d731 --- /dev/null +++ b/src/fu-hash.py @@ -0,0 +1,33 @@ +#!/usr/bin/python3 +""" Builds a header for the plugins to include """ + +# pylint: disable=invalid-name,wrong-import-position,pointless-string-statement + +""" +SPDX-License-Identifier: LGPL-2.1+ +""" + +import sys +import hashlib + +def usage(return_code): + """ print usage and exit with the supplied return code """ + if return_code == 0: + out = sys.stdout + else: + out = sys.stderr + out.write("usage: fu-hash.py
        ") + sys.exit(return_code) + +if __name__ == '__main__': + if {'-?', '--help', '--usage'}.intersection(set(sys.argv)): + usage(0) + if len(sys.argv) != 3: + usage(1) + with open(sys.argv[1], 'rb') as f: + buf = f.read() + csum = hashlib.sha256(buf).hexdigest() + with open(sys.argv[2], 'w') as f2: + f2.write('#ifndef FU_BUILD_HASH\n') + f2.write('#define FU_BUILD_HASH "%s"\n' % csum) + f2.write('#endif /* FU_BUILD_HASH */\n') diff --git a/src/fu-main.c b/src/fu-main.c index 98efb4135..0a2b9dae4 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1115,6 +1115,9 @@ fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender, if (g_strcmp0 (property_name, "DaemonVersion") == 0) return g_variant_new_string (VERSION); + if (g_strcmp0 (property_name, "Tainted") == 0) + return g_variant_new_boolean (fu_engine_get_tainted (priv->engine)); + if (g_strcmp0 (property_name, "Status") == 0) return g_variant_new_uint32 (fu_engine_get_status (priv->engine)); diff --git a/src/fu-plugin-private.h b/src/fu-plugin-private.h index bb40c3ca4..cb25b4976 100644 --- a/src/fu-plugin-private.h +++ b/src/fu-plugin-private.h @@ -38,6 +38,7 @@ void fu_plugin_set_priority (FuPlugin *self, guint priority); void fu_plugin_set_name (FuPlugin *self, const gchar *name); +const gchar *fu_plugin_get_build_hash (FuPlugin *self); GPtrArray *fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule); gboolean fu_plugin_has_rule (FuPlugin *self, diff --git a/src/fu-plugin-vfuncs.h b/src/fu-plugin-vfuncs.h index 52dc368e0..63289355f 100644 --- a/src/fu-plugin-vfuncs.h +++ b/src/fu-plugin-vfuncs.h @@ -9,6 +9,7 @@ #include "fu-plugin.h" #include "fu-device.h" +#include "fu-hash.h" G_BEGIN_DECLS diff --git a/src/fu-plugin.c b/src/fu-plugin.c index 882918b83..b403d9538 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -44,6 +44,7 @@ typedef struct { guint priority; GPtrArray *rules[FU_PLUGIN_RULE_LAST]; gchar *name; + gchar *build_hash; FuHwids *hwids; FuQuirks *quirks; GHashTable *runtime_versions; @@ -132,6 +133,34 @@ fu_plugin_set_name (FuPlugin *self, const gchar *name) priv->name = g_strdup (name); } +/** + * fu_plugin_set_build_hash: + * @self: A #FuPlugin + * @build_hash: A checksum + * + * Sets the plugin build hash, typically a SHA256 checksum. All plugins must + * set the correct checksum to avoid the daemon being marked as tainted. + * + * Since: 1.2.4 + **/ +void +fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_PLUGIN (self)); + g_return_if_fail (build_hash != NULL); + g_free (priv->build_hash); + priv->build_hash = g_strdup (build_hash); +} + +const gchar * +fu_plugin_get_build_hash (FuPlugin *self) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); + return priv->build_hash; +} + /** * fu_plugin_cache_lookup: * @self: A #FuPlugin diff --git a/src/fu-plugin.h b/src/fu-plugin.h index a7655f9db..bc738951c 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -97,6 +97,8 @@ FuPluginData *fu_plugin_alloc_data (FuPlugin *self, gboolean fu_plugin_get_enabled (FuPlugin *self); void fu_plugin_set_enabled (FuPlugin *self, gboolean enabled); +void fu_plugin_set_build_hash (FuPlugin *self, + const gchar *build_hash); GUsbContext *fu_plugin_get_usb_context (FuPlugin *self); void fu_plugin_device_add (FuPlugin *self, FuDevice *device); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 090d46375..7a28a33e6 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -31,6 +31,7 @@ #include "fu-plugin-private.h" #include "fu-plugin-list.h" #include "fu-progressbar.h" +#include "fu-hash.h" #include "fu-hwids.h" #include "fu-smbios.h" #include "fu-test.h" @@ -455,6 +456,7 @@ fu_engine_partial_hash_func (void) /* set up dummy plugin */ fu_plugin_set_name (plugin, "test"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_engine_add_plugin (engine, plugin); /* add two dummy devices */ @@ -1800,6 +1802,34 @@ fu_plugin_quirks_device_func (void) g_assert (fu_device_has_flag (device_tmp, FWUPD_DEVICE_FLAG_UPDATABLE)); } +static void +fu_plugin_hash_func (void) +{ + GError *error = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuPlugin) plugin = fu_plugin_new (); + gboolean ret = FALSE; + + ret = fu_engine_load (engine, &error); + g_assert_no_error (error); + g_assert (ret); + + /* make sure not tainted */ + ret = fu_engine_get_tainted (engine); + g_assert_false (ret); + + /* create a tainted plugin */ + g_setenv ("FWUPD_PLUGIN_TEST", "build-hash", TRUE); + ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); + g_assert_no_error (error); + + /* make sure it tainted now */ + g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, "* has incorrect built version*"); + fu_engine_add_plugin (engine, plugin); + ret = fu_engine_get_tainted (engine); + g_assert_true (ret); +} + static void fu_plugin_module_func (void) { @@ -3301,6 +3331,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/plugin{composite}", fu_plugin_composite_func); g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func); g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func); + g_test_add_func ("/fwupd/plugin{build-hash}", fu_plugin_hash_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func); g_test_add_func ("/fwupd/common{guid}", fu_common_guid_func); diff --git a/src/fu-tool.c b/src/fu-tool.c index dfd4193ae..c40e992db 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -120,7 +120,13 @@ fu_util_start_engine (FuUtilPrivate *priv, GError **error) } } - return fu_engine_load (priv->engine, error); + if (!fu_engine_load (priv->engine, error)) + return FALSE; + if (fu_engine_get_tainted (priv->engine)) { + g_printerr ("WARNING: This tool has loaded 3rd party code and " + "is no longer supported by the upstream developers!\n"); + } + return TRUE; } static gint diff --git a/src/fu-util.c b/src/fu-util.c index 339418808..cbe189814 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2609,6 +2609,17 @@ main (int argc, char *argv[]) return EXIT_SUCCESS; } + /* show a warning if the daemon is tainted */ + if (!fwupd_client_connect (priv->client, priv->cancellable, &error)) { + g_printerr ("Failed to connect to daemon: %s\n", + error->message); + return EXIT_FAILURE; + } + if (fwupd_client_get_tainted (priv->client)) { + g_printerr ("WARNING: The daemon has loaded 3rd party code and " + "is no longer supported by the upstream developers!\n"); + } + /* run the specified command */ ret = fu_util_run (priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { diff --git a/src/meson.build b/src/meson.build index 99e16a4d0..286d4fc14 100644 --- a/src/meson.build +++ b/src/meson.build @@ -107,9 +107,19 @@ resources_src = gnome.compile_resources( c_name : 'fu' ) +fu_hash = custom_target( + 'fu-hash.h', + input : libfwupdprivate, + output : 'fu-hash.h', + command : [python3.path(), + join_paths(meson.current_source_dir(), 'fu-hash.py'), + '@INPUT@', '@OUTPUT@'] +) + fwupdtool = executable( 'fwupdtool', resources_src, + fu_hash, sources : [ 'fu-tool.c', keyring_src, @@ -251,6 +261,7 @@ executable( install : true, install_dir : join_paths(libexecdir, 'fwupd') ) + endif if get_option('tests') @@ -265,6 +276,7 @@ if get_option('tests') hwid_test_firmware, noreqs_test_firmware, test_deps, + fu_hash, sources : [ keyring_src, 'fu-self-test.c', diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 7d06d97f3..23ff36a5c 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -22,6 +22,17 @@ + + + + + + If the daemon has been tainted with a 3rd party plugin. + + + + + From 818071d178628ccadfe1e3c53623aa83282b5ad8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 17 Jan 2019 09:40:52 +0000 Subject: [PATCH 187/254] uefi: Refactor and simplify the EFI loader --- plugins/uefi/efi/fwup-cleanups.h | 23 + plugins/uefi/efi/fwup-common.c | 127 ++++ plugins/uefi/efi/fwup-common.h | 23 + plugins/uefi/efi/fwup-debug.c | 80 +++ plugins/uefi/efi/fwup-debug.h | 32 + plugins/uefi/efi/fwup-efi.c | 58 ++ plugins/uefi/efi/fwup-efi.h | 68 +- plugins/uefi/efi/fwupdate.c | 1002 ++++++++---------------------- plugins/uefi/efi/meson.build | 19 +- 9 files changed, 673 insertions(+), 759 deletions(-) create mode 100644 plugins/uefi/efi/fwup-cleanups.h create mode 100644 plugins/uefi/efi/fwup-common.c create mode 100644 plugins/uefi/efi/fwup-common.h create mode 100644 plugins/uefi/efi/fwup-debug.c create mode 100644 plugins/uefi/efi/fwup-debug.h create mode 100644 plugins/uefi/efi/fwup-efi.c diff --git a/plugins/uefi/efi/fwup-cleanups.h b/plugins/uefi/efi/fwup-cleanups.h new file mode 100644 index 000000000..ff5328f7c --- /dev/null +++ b/plugins/uefi/efi/fwup-cleanups.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define _DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ + static inline VOID name(VOID *v) \ + { \ + if (*(Type*)v) \ + func (*(Type*)v); \ + } +_DEFINE_CLEANUP_FUNCTION0(VOID *, _FreePool_p, FreePool) +#define _cleanup_free __attribute__ ((cleanup(_FreePool_p))) + +static inline VOID * +_steal_pointer(VOID *pp) +{ + VOID **ptr = (VOID **) pp; + VOID *ref = *ptr; + *ptr = NULL; + return ref; +} diff --git a/plugins/uefi/efi/fwup-common.c b/plugins/uefi/efi/fwup-common.c new file mode 100644 index 000000000..b7ff19980 --- /dev/null +++ b/plugins/uefi/efi/fwup-common.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-debug.h" +#include "fwup-common.h" + +VOID +fwup_msleep(unsigned long msecs) +{ + BS->Stall(msecs); +} + +/* + * Allocate some raw pages that aren't part of the pool allocator. + */ +VOID * +fwup_malloc_raw(UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); /* page size is always 4096 */ + EFI_STATUS rc; + EFI_PHYSICAL_ADDRESS pageaddr = 0; + EFI_ALLOCATE_TYPE type = AllocateAnyPages; + + if (sizeof(VOID *) == 4) { + pageaddr = 0xffffffffULL - 8192; + type = AllocateMaxAddress; + } + + rc = uefi_call_wrapper(BS->AllocatePages, 4, type, + EfiLoaderData, pages, + &pageaddr); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not allocate %d", size); + return NULL; + } + if (sizeof(VOID *) == 4 && pageaddr > 0xffffffffULL) { + uefi_call_wrapper(BS->FreePages, 2, pageaddr, pages); + fwup_warning(L"Got bad allocation at 0x%016x", (UINT64)pageaddr); + return NULL; + } + return (VOID *)(UINTN)pageaddr; +} + +/* + * Free our raw page allocations. + */ +static EFI_STATUS +fwup_free_raw(VOID *addr, UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); + return uefi_call_wrapper(BS->FreePages, 2, + (EFI_PHYSICAL_ADDRESS)(UINTN)addr, pages); +} + +VOID * +fwup_malloc (UINTN size) +{ + VOID *addr = AllocatePool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +VOID * +fwup_malloc0 (UINTN size) +{ + VOID *addr = AllocateZeroPool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +EFI_STATUS +fwup_time(EFI_TIME *ts) +{ + EFI_TIME_CAPABILITIES timecaps = { 0, }; + return uefi_call_wrapper(RT->GetTime, 2, ts, &timecaps); +} + +EFI_STATUS +fwup_read_file(EFI_FILE_HANDLE fh, UINT8 **buf_out, UINTN *buf_size_out) +{ + const UINTN bs = 512; + UINTN i = 0; + UINTN n_blocks = 4096; + UINT8 *buf = NULL; + + while (1) { + VOID *newb = NULL; + UINTN news = n_blocks * bs * 2; + + newb = fwup_malloc_raw(news); + if (newb == NULL) + return EFI_OUT_OF_RESOURCES; + if (buf != NULL) { + CopyMem(newb, buf, bs * n_blocks); + fwup_free_raw(buf, bs * n_blocks); + } + buf = newb; + n_blocks *= 2; + + for (; i < n_blocks; i++) { + EFI_STATUS rc; + UINTN sz = bs; + + rc = uefi_call_wrapper(fh->Read, 3, fh, &sz, &buf[i * bs]); + if (EFI_ERROR(rc)) { + fwup_free_raw(buf, bs * n_blocks); + fwup_warning(L"Could not read file: %r", rc); + return rc; + } + + if (sz != bs) { + *buf_size_out = bs * i + sz; + *buf_out = buf; + return EFI_SUCCESS; + } + } + } + return EFI_SUCCESS; +} diff --git a/plugins/uefi/efi/fwup-common.h b/plugins/uefi/efi/fwup-common.h new file mode 100644 index 000000000..9ea12e90c --- /dev/null +++ b/plugins/uefi/efi/fwup-common.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef _FWUP_COMMON_H +#define _FWUP_COMMON_H + +#include "fwup-efi.h" + +VOID fwup_msleep (unsigned long msecs); +EFI_STATUS fwup_time (EFI_TIME *ts); +EFI_STATUS fwup_read_file (EFI_FILE_HANDLE fh, + UINT8 **buf_out, + UINTN *buf_size_out); +VOID *fwup_malloc_raw (UINTN size); + +VOID *fwup_malloc (UINTN size); +VOID *fwup_malloc0 (UINTN size); + +#endif /* _FWUP_COMMON_H */ diff --git a/plugins/uefi/efi/fwup-debug.c b/plugins/uefi/efi/fwup-debug.c new file mode 100644 index 000000000..c5c3f5636 --- /dev/null +++ b/plugins/uefi/efi/fwup-debug.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +static UINT8 debugging = FALSE; + +UINT8 +fwup_debug_get_enabled(VOID) +{ + return debugging; +} + +VOID +fwup_debug_set_enabled(UINT8 val) +{ + debugging = val; +} + +static VOID +fwupd_debug_efivar_append(CHAR16 *out1) +{ + CHAR16 *name = L"FWUPDATE_DEBUG_LOG"; + UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + static UINT8 once = TRUE; + if (once) { + once = FALSE; + fwup_delete_variable(name, &fwupdate_guid, attrs); + } else { + attrs |= EFI_VARIABLE_APPEND_WRITE; + } + fwup_set_variable(name, &fwupdate_guid, out1, StrSize(out1) - sizeof(CHAR16), attrs); +} + +VOID +fwup_log(FwupLogLevel level, const char *func, const char *file, const int line, CHAR16 *fmt, ...) +{ + va_list args; + _cleanup_free CHAR16 *tmp = NULL; + + va_start(args, fmt); + tmp = VPoolPrint(fmt, args); + va_end(args); + if (tmp == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + + if (debugging) { + _cleanup_free CHAR16 *out1 = NULL; + out1 = PoolPrint(L"%a:%d:%a(): %s", file, line, func, tmp); + if (out1 == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + Print(L"%s\n", out1); + fwupd_debug_efivar_append(out1); + } else { + switch (level) { + case FWUP_DEBUG_LEVEL_DEBUG: + break; + case FWUP_DEBUG_LEVEL_WARNING: + Print(L"WARNING: %s\n", tmp); + break; + default: + Print(L"%s\n", tmp); + break; + } + } +} diff --git a/plugins/uefi/efi/fwup-debug.h b/plugins/uefi/efi/fwup-debug.h new file mode 100644 index 000000000..39b72c800 --- /dev/null +++ b/plugins/uefi/efi/fwup-debug.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef _FWUP_DEBUG_H +#define _FWUP_DEBUG_H + +typedef enum { + FWUP_DEBUG_LEVEL_DEBUG, + FWUP_DEBUG_LEVEL_INFO, + FWUP_DEBUG_LEVEL_WARNING, + FWUP_DEBUG_LEVEL_LAST +} FwupLogLevel; + +VOID fwup_log (FwupLogLevel level, + const char *func, + const char *file, + const int line, + CHAR16 *fmt, + ...); + +UINT8 fwup_debug_get_enabled (VOID); +VOID fwup_debug_set_enabled (UINT8 val); + +#define fwup_debug(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_DEBUG, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_info(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_INFO, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_warning(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_WARNING, __func__, __FILE__, __LINE__, fmt, ## args ) + +#endif /* _FWUP_DEBUG_H */ diff --git a/plugins/uefi/efi/fwup-efi.c b/plugins/uefi/efi/fwup-efi.c new file mode 100644 index 000000000..05e7fa196 --- /dev/null +++ b/plugins/uefi/efi/fwup-efi.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-common.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +EFI_STATUS +fwup_delete_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs) +{ + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, 0, NULL); +} + +EFI_STATUS +fwup_set_variable(CHAR16 *name, EFI_GUID *guid, VOID *data, UINTN size, UINT32 attrs) +{ + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, size, data); +} + +EFI_STATUS +fwup_get_variable(CHAR16 *name, EFI_GUID *guid, VOID **buf_out, UINTN *buf_size_out, UINT32 *attrs_out) +{ + EFI_STATUS rc; + UINTN size = 0; + UINT32 attrs; + _cleanup_free VOID *buf = NULL; + + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_BUFFER_TOO_SMALL) { + buf = fwup_malloc(size); + if (buf == NULL) + return EFI_OUT_OF_RESOURCES; + } else if (rc != EFI_NOT_FOUND) { + fwup_debug(L"Could not get variable '%s': %r", name, rc); + return rc; + } + } else { + fwup_debug(L"GetVariable(%s) succeeded with size=0", name); + return EFI_INVALID_PARAMETER; + } + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, buf); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable '%s': %r", name, rc); + return rc; + } + *buf_out = _steal_pointer(&buf); + *buf_size_out = size; + *attrs_out = attrs; + return EFI_SUCCESS; +} diff --git a/plugins/uefi/efi/fwup-efi.h b/plugins/uefi/efi/fwup-efi.h index 5d55a85b1..f7b43b2da 100644 --- a/plugins/uefi/efi/fwup-efi.h +++ b/plugins/uefi/efi/fwup-efi.h @@ -12,40 +12,62 @@ #define UPDATE_INFO_VERSION 7 -#ifdef _EFI_INCLUDE_ -#define efidp_header EFI_DEVICE_PATH -#define efi_guid_t EFI_GUID -#endif /* _EFI_INCLUDE_ */ +static __attribute__((__unused__)) EFI_GUID empty_guid = + {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}; +static __attribute__((__unused__))EFI_GUID fwupdate_guid = + {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; +static __attribute__((__unused__))EFI_GUID ux_capsule_guid = + {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; +static __attribute__((__unused__))EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; typedef struct { - uint8_t version; - uint8_t checksum; - uint8_t image_type; - uint8_t reserved; - uint32_t mode; - uint32_t x_offset; - uint32_t y_offset; -} ux_capsule_header_t; + UINT8 version; + UINT8 checksum; + UINT8 image_type; + UINT8 reserved; + UINT32 mode; + UINT32 x_offset; + UINT32 y_offset; +} __attribute__((__packed__)) UX_CAPSULE_HEADER; -typedef struct update_info_s { - uint32_t update_info_version; +typedef struct { + UINT32 update_info_version; /* stuff we need to apply an update */ - efi_guid_t guid; - uint32_t capsule_flags; - uint64_t hw_inst; + EFI_GUID guid; + UINT32 capsule_flags; + UINT64 hw_inst; - EFI_TIME time_attempted; + EFI_TIME time_attempted; /* our metadata */ - uint32_t status; + UINT32 status; /* variadic device path */ union { - efidp_header *dp_ptr; - efidp_header dp; - uint8_t dp_buf[0]; + EFI_DEVICE_PATH dp; + UINT8 dp_buf[0]; }; -} __attribute__((__packed__)) update_info; +} __attribute__((__packed__)) FWUP_UPDATE_INFO; + +typedef struct { + UINT32 attributes; + UINT16 file_path_list_length; + CHAR16 *description; +} __attribute__((__packed__)) EFI_LOAD_OPTION; + +EFI_STATUS fwup_delete_variable (CHAR16 *name, + EFI_GUID *guid, + UINT32 attrs); +EFI_STATUS fwup_set_variable (CHAR16 *name, + EFI_GUID *guid, + VOID *data, + UINTN size, + UINT32 attrs); +EFI_STATUS fwup_get_variable (CHAR16 *name, + EFI_GUID *guid, + VOID **buf_out, + UINTN *buf_size_out, + UINT32 *attrs_out); #endif /* _FWUP_EFI_H */ diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index e4796d1ed..8645b11ce 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -7,298 +7,37 @@ #include #include -#include - +#include "fwup-cleanups.h" +#include "fwup-common.h" #include "fwup-efi.h" +#include "fwup-debug.h" #define UNUSED __attribute__((__unused__)) +#define GNVN_BUF_SIZE 1024 +#define FWUP_NUM_CAPSULE_UPDATES_MAX 128 -EFI_GUID empty_guid = {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}; -EFI_GUID fwupdate_guid = - {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; -EFI_GUID ux_capsule_guid = - {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; -EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; +typedef struct { + CHAR16 *name; + UINT32 attrs; + UINTN size; + FWUP_UPDATE_INFO *info; +} FWUP_UPDATE_TABLE; +VOID +fwup_update_table_free(FWUP_UPDATE_TABLE *update) +{ + FreePool(update->info); + FreePool(update->name); + FreePool(update); +} -typedef struct update_table_s { - CHAR16 *name; - UINT32 attributes; - UINTN size; - update_info *info; -} update_table; - -static EFI_STATUS -delete_variable(CHAR16 *name, EFI_GUID guid, UINT32 attributes); -static EFI_STATUS -set_variable(CHAR16 *name, EFI_GUID guid, VOID *data, UINTN size, - UINT32 attrs); - -static int debugging; +_DEFINE_CLEANUP_FUNCTION0(FWUP_UPDATE_TABLE *, _fwup_update_table_free_p, fwup_update_table_free) +#define _cleanup_update_table __attribute__ ((cleanup(_fwup_update_table_free_p))) #define SECONDS 1000000 -static VOID -msleep(unsigned long msecs) -{ - BS->Stall(msecs); -} - - -/* - * I'm not actually sure when these appear, but they're present in the - * version in front of me. - */ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) -#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1 -#define uintn_mult(a, b, c) __builtin_mul_overflow(a, b, c) -#endif -#endif -#ifndef uintn_mult -#define uintn_mult(a, b, c) ({ \ - const UINTN _limit = ~0UL; \ - int _ret = 1; \ - if ((a) != 0 && (b) != 0) { \ - _ret = _limit / (a) < (b); \ - } \ - if (!_ret) \ - *(c) = ((a) * (b)); \ - _ret; \ - }) -#endif - -/* use GCC __cleanup__ */ -#define _DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ - static inline void name(void *v) \ - { \ - if (*(Type*)v) \ - func (*(Type*)v); \ - } -_DEFINE_CLEANUP_FUNCTION0(void *, _FreePool_p, FreePool) -#define _cleanup_FreePool __attribute__ ((cleanup(_FreePool_p))) - -static inline void * -_steal_pointer(void *pp) -{ - void **ptr = (void **) pp; - void *ref = *ptr; - *ptr = NULL; - return ref; -} - -int -debug_print(const char *func, const char *file, const int line, - CHAR16 *fmt, ...) -{ - va_list args0, args1; - _cleanup_FreePool CHAR16 *out0 = NULL; - _cleanup_FreePool CHAR16 *out1 = NULL; - UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; - CHAR16 *name = L"FWUPDATE_DEBUG_LOG"; - static bool once = true; - - va_start(args0, fmt); - out0 = VPoolPrint(fmt, args0); - va_end(args0); - if (!out0) { - if (debugging) { - va_start(args1, fmt); - VPrint(fmt, args1); - va_end(args1); - msleep(200000); - } - Print(L"fwupdate: Allocation for debug log failed!\n"); - return debugging; - } - if (debugging) - Print(L"%s", out0); - out1 = PoolPrint(L"%a:%d:%a(): %s", file, line, func, out0); - if (!out1) { - Print(L"fwupdate: Allocation for debug log failed!\n"); - return debugging; - } - - if (once) { - once = false; - delete_variable(name, fwupdate_guid, attrs); - } else { - attrs |= EFI_VARIABLE_APPEND_WRITE; - } - set_variable(name, fwupdate_guid, out1, StrSize(out1) - sizeof (CHAR16), attrs); - - return debugging; -} - -#define dprint(fmt, args...) debug_print(__func__, __FILE__, __LINE__, fmt, ## args ) -#define print(fmt, args...) ({ if (!dprint(fmt, ## args)) Print(fmt, ## args); }) - -/* - * Allocate some raw pages that aren't part of the pool allocator. - */ -static EFI_STATUS -allocate(void **addr, UINTN size) -{ - /* - * We're actually guaranteed that page size is 4096 by UEFI. - */ - UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); - EFI_STATUS rc; - EFI_PHYSICAL_ADDRESS pageaddr = 0; - EFI_ALLOCATE_TYPE type = AllocateAnyPages; - - if (sizeof (VOID *) == 4) { - pageaddr = 0xffffffffULL - 8192; - type = AllocateMaxAddress; - } - - rc = uefi_call_wrapper(BS->AllocatePages, 4, type, - EfiLoaderData, pages, - &pageaddr); - if (EFI_ERROR(rc)) - return rc; - if (sizeof (VOID *) == 4 && pageaddr > 0xffffffffULL) { - uefi_call_wrapper(BS->FreePages, 2, pageaddr, pages); - print(L"Got bad allocation at 0x%016x\n", (UINT64)pageaddr); - return EFI_OUT_OF_RESOURCES; - } - *addr = (void *)(UINTN)pageaddr; - return rc; -} - -/* - * Free our raw page allocations. - */ -static EFI_STATUS -free(void *addr, UINTN size) -{ - UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); - EFI_STATUS rc; - - rc = uefi_call_wrapper(BS->FreePages, 2, - (EFI_PHYSICAL_ADDRESS)(UINTN)addr, - pages); - return rc; -} - -static inline int -guid_cmp(efi_guid_t *a, efi_guid_t *b) -{ - return CompareMem(a, b, sizeof (*a)); -} - -EFI_STATUS -read_file(EFI_FILE_HANDLE fh, UINT8 **buf_out, UINTN *buf_size_out) -{ - UINT8 *b = NULL; - const UINTN bs = 512; - UINTN n_blocks = 4096; - UINTN i = 0; - EFI_STATUS rc; - - while (1) { - void *newb = NULL; - UINTN news = 0; - if (uintn_mult(bs * 2, n_blocks, &news)) { - if (b) - free(b, bs * n_blocks); - print(L"allocation %d * %d would overflow size\n", - bs * 2, n_blocks); - return EFI_OUT_OF_RESOURCES; - } - rc = allocate(&newb, news); - if (EFI_ERROR(rc)) { - print(L"Tried to allocate %d\n", - bs * n_blocks * 2); - print(L"Could not allocate memory.\n"); - return EFI_OUT_OF_RESOURCES; - } - if (b) { - CopyMem(newb, b, bs * n_blocks); - free(b, bs * n_blocks); - } - b = newb; - n_blocks *= 2; - - for (; i < n_blocks; i++) { - EFI_STATUS rc; - UINTN sz = bs; - - rc = uefi_call_wrapper(fh->Read, 3, fh, &sz, - &b[i * bs]); - if (EFI_ERROR(rc)) { - free(b, bs * n_blocks); - print(L"Could not read file: %r\n", rc); - return rc; - } - - if (sz != bs) { - *buf_size_out = bs * i + sz; - *buf_out = b; - return EFI_SUCCESS; - } - } - } - return EFI_SUCCESS; -} - -static EFI_STATUS -delete_variable(CHAR16 *name, EFI_GUID guid, UINT32 attributes) -{ - return uefi_call_wrapper(RT->SetVariable, 5, name, &guid, attributes, - 0, NULL); -} - -static EFI_STATUS -set_variable(CHAR16 *name, EFI_GUID guid, VOID *data, UINTN size, - UINT32 attrs) -{ - return uefi_call_wrapper(RT->SetVariable, 5, name, &guid, attrs, - size, data); -} - -static EFI_STATUS -read_variable(CHAR16 *name, EFI_GUID guid, void **buf_out, UINTN *buf_size_out, - UINT32 *attributes_out) -{ - EFI_STATUS rc; - UINT32 attributes; - UINTN size = 0; - _cleanup_FreePool void *buf = NULL; - - rc = uefi_call_wrapper(RT->GetVariable, 5, name, - &guid, &attributes, &size, NULL); - if (EFI_ERROR(rc)) { - if (rc == EFI_BUFFER_TOO_SMALL) { - buf = AllocatePool(size); - if (!buf) { - print(L"Tried to allocate %d\n", size); - print(L"Could not allocate memory.\n"); - return EFI_OUT_OF_RESOURCES; - } - } else if (rc != EFI_NOT_FOUND) { - print(L"Could not get variable \"%s\": %r\n", name, rc); - return rc; - } - } else { - print(L"GetVariable(%s) succeeded with size=0.\n", name); - return EFI_INVALID_PARAMETER; - } - rc = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, &attributes, - &size, buf); - if (EFI_ERROR(rc)) { - print(L"Could not get variable \"%s\": %r\n", name, rc); - return rc; - } - *buf_out = _steal_pointer(&buf); - *buf_size_out = size; - *attributes_out = attributes; - return EFI_SUCCESS; -} - static INTN -dp_size(EFI_DEVICE_PATH *dp, INTN limit) +fwup_dp_size(EFI_DEVICE_PATH *dp, INTN limit) { INTN ret = 0; while (1) { @@ -318,270 +57,150 @@ dp_size(EFI_DEVICE_PATH *dp, INTN limit) } static EFI_STATUS -get_info(CHAR16 *name, update_table *info_out) +fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) { EFI_STATUS rc; - update_info *info = NULL; + FWUP_UPDATE_INFO *info = NULL; UINTN info_size = 0; - UINT32 attributes = 0; - void *info_ptr = NULL; + UINT32 attrs = 0; + VOID *info_ptr = NULL; - rc = read_variable(name, fwupdate_guid, &info_ptr, &info_size, - &attributes); + rc = fwup_get_variable(name, &fwupdate_guid, &info_ptr, &info_size, &attrs); if (EFI_ERROR(rc)) return rc; - info = (update_info *)info_ptr; + info = (FWUP_UPDATE_INFO *)info_ptr; - if (info_size < sizeof (*info)) { - print(L"Update \"%s\" is is too small.\n", name); - delete_variable(name, fwupdate_guid, attributes); + if (info_size < sizeof(*info)) { + fwup_warning(L"Update '%s' is is too small", name); + fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } - if (info_size - sizeof (EFI_DEVICE_PATH) <= sizeof (*info)) { - print(L"Update \"%s\" is malformed, " - L"and cannot hold a file path.\n", name); - delete_variable(name, fwupdate_guid, attributes); + if (info_size - sizeof(EFI_DEVICE_PATH) <= sizeof(*info)) { + fwup_warning(L"Update '%s' is malformed, " + L"and cannot hold a file path", name); + fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } EFI_DEVICE_PATH *hdr = (EFI_DEVICE_PATH *)&info->dp; - INTN is = EFI_FIELD_OFFSET(update_info, dp); + INTN is = EFI_FIELD_OFFSET(FWUP_UPDATE_INFO, dp); if (is > (INTN)info_size) { - print(L"Update \"%s\" has an invalid file path.\n" - L"Device path offset is %d, but total size is %d\n", - name, is, info_size); - delete_variable(name, fwupdate_guid, attributes); + fwup_warning(L"Update '%s' has an invalid file path, " + L"device path offset is %d, but total size is %d", + name, is, info_size); + fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } is = info_size - is; - INTN sz = dp_size(hdr, info_size); - if (sz < 0 || is < 0) { -invalid_size: - print(L"Update \"%s\" has an invalid file path.\n" - L"update info size: %d dp size: %d size for dp: %d\n", - name, info_size, sz, is); - delete_variable(name, fwupdate_guid, attributes); + INTN sz = fwup_dp_size(hdr, info_size); + if (sz < 0 || is < 0 || is > (INTN)info_size || is != sz) { + fwup_warning(L"Update '%s' has an invalid file path, " + L"update info size: %d dp size: %d size for dp: %d", + name, info_size, sz, is); + fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } - if (is > (INTN)info_size) - goto invalid_size; - if (is != sz) - goto invalid_size; info_out->info = info; info_out->size = info_size; - info_out->attributes = attributes; + info_out->attrs = attrs; + info_out->name = StrDuplicate(name); + if (info_out->name == NULL) { + fwup_warning(L"Could not allocate %d", StrSize(name)); + return EFI_OUT_OF_RESOURCES; + } return EFI_SUCCESS; } static EFI_STATUS -find_updates(UINTN *n_updates_out, update_table ***updates_out) +fwup_populate_update_table(FWUP_UPDATE_TABLE **updates, UINTN *n_updates_out) { - EFI_STATUS rc; - _cleanup_FreePool update_table **updates = NULL; - UINTN n_updates = 0; - UINTN n_updates_allocated = 128; - EFI_STATUS ret = EFI_OUT_OF_RESOURCES; - -#define GNVN_BUF_SIZE 1024 - UINTN variable_name_allocation = GNVN_BUF_SIZE; - UINTN variable_name_size = 0; - _cleanup_FreePool CHAR16 *variable_name = NULL; EFI_GUID vendor_guid = empty_guid; - UINTN mult_res; - - if (uintn_mult(sizeof (update_table *), n_updates_allocated, - &mult_res)) { - print(L"Allocation %d * %d would overflow size\n", - sizeof (update_table *), n_updates_allocated); - return EFI_OUT_OF_RESOURCES; - } - - updates = AllocateZeroPool(mult_res); - if (!updates) { - print(L"Tried to allocate %d\n", mult_res); - print(L"Could not allocate memory.\n"); - return EFI_OUT_OF_RESOURCES; - } + EFI_STATUS rc; + UINTN n_updates = 0; + _cleanup_free CHAR16 *variable_name = NULL; /* How much do we trust "size of the VariableName buffer" to mean * sizeof(vn) and not sizeof(vn)/sizeof(vn[0]) ? */ - variable_name = AllocateZeroPool(GNVN_BUF_SIZE * 2); - if (!variable_name) { - print(L"Tried to allocate %d\n", GNVN_BUF_SIZE * 2); - print(L"Could not allocate memory.\n"); + variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); + if (variable_name == NULL) return EFI_OUT_OF_RESOURCES; - } while (1) { - variable_name_size = variable_name_allocation; + UINTN variable_name_size = GNVN_BUF_SIZE; rc = uefi_call_wrapper(RT->GetNextVariableName, 3, &variable_name_size, variable_name, &vendor_guid); - if (rc == EFI_BUFFER_TOO_SMALL) { - /* If we don't have a big enough buffer to hold the - * name, allocate a bigger one and try again */ - UINTN new_allocation; - CHAR16 *new_name; - - new_allocation = variable_name_size; - if (uintn_mult(new_allocation, 2, &mult_res)) { - print(L"%d * 2 would overflow size\n", - new_allocation); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - new_name = AllocatePool(new_allocation * 2); - if (!new_name) { - print(L"Tried to allocate %d\n", - new_allocation * 2); - print(L"Could not allocate memory.\n"); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - CopyMem(new_name, variable_name, - variable_name_allocation); - variable_name_allocation = new_allocation; - FreePool(variable_name); - variable_name = new_name; - continue; - } else if (rc == EFI_NOT_FOUND) { + if (rc == EFI_NOT_FOUND) break; - } else if (EFI_ERROR(rc)) { - print(L"Could not get variable name: %r\n", rc); - ret = rc; - goto err; + + /* ignore any huge names */ + if (rc == EFI_BUFFER_TOO_SMALL) + continue; + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable name: %r", rc); + return rc; } - /* - * If it's not one of our state variables, keep going. - */ - if (guid_cmp(&vendor_guid, &fwupdate_guid)) + /* not one of our state variables */ + if (CompareGuid(&vendor_guid, &fwupdate_guid)) continue; - /* - * Don't delete our debugging settings. - */ + /* ignore debugging settings */ if (StrCmp(variable_name, L"FWUPDATE_VERBOSE") == 0 || StrCmp(variable_name, L"FWUPDATE_DEBUG_LOG") == 0) continue; - UINTN vns = StrLen(variable_name); - CHAR16 vn[vns + 1]; - CopyMem(vn, variable_name, vns * sizeof (vn[0])); - vn[vns] = L'\0'; - print(L"Found update %s\n", vn); - - if (n_updates == n_updates_allocated) { - update_table **new_ups = NULL; - UINTN mul_a, mul_b; - if (uintn_mult(n_updates_allocated, 2, &mult_res)) { - mul_a = n_updates_allocated; - mul_b = 2; -mult_err: - print(L"Allocation %d * %d would overflow size\n", - mul_a, mul_b); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - if (uintn_mult(mult_res, sizeof (update_table *), - &mult_res)) { - mul_a = mult_res; - mul_b = sizeof (update_table *); - goto mult_err; - } - - new_ups = AllocateZeroPool(mult_res); - if (!new_ups) { - print(L"Tried to allocate %d\n", mult_res); - print(L"Could not allocate memory.\n"); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - CopyMem(new_ups, updates, mult_res); - n_updates_allocated *= 2; - FreePool(updates); - updates = new_ups; + if (n_updates > FWUP_NUM_CAPSULE_UPDATES_MAX) { + fwup_warning(L"Ignoring update %s", variable_name); + continue; } - update_table *update = AllocatePool(sizeof (update_table)); - if (!update) { - print(L"Tried to allocate %d\n", sizeof (update_table)); - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - - update->name = StrDuplicate(vn); - if (!update->name) { - print(L"Tried to allocate %d\n", StrSize(vn)); - ret = EFI_OUT_OF_RESOURCES; - FreePool(update); - goto err; - } - - rc = get_info(vn, update); + fwup_info(L"Found update %s", variable_name); + _cleanup_update_table FWUP_UPDATE_TABLE *update = fwup_malloc0(sizeof(FWUP_UPDATE_TABLE)); + if (update == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_info(variable_name, update); if (EFI_ERROR(rc)) { - print(L"Could not get update info for \"%s\", aborting.\n", vn); - ret = rc; - FreePool(update->name); - FreePool(update); - goto err; + fwup_warning(L"Could not populate update info for '%s'", variable_name); + return rc; } if (update->info->status & FWUPDATE_ATTEMPT_UPDATE) { - EFI_TIME_CAPABILITIES timecaps = { 0, }; - - uefi_call_wrapper(RT->GetTime, 2, - &update->info->time_attempted, - &timecaps); + fwup_time(&update->info->time_attempted); update->info->status = FWUPDATE_ATTEMPTED; - updates[n_updates++] = update; - } else { - FreePool(update->info); - FreePool(update->name); - FreePool(update); + updates[n_updates++] = _steal_pointer(&update); } } *n_updates_out = n_updates; - *updates_out = _steal_pointer(&updates); - return EFI_SUCCESS; -err: - for (unsigned int i = 0; i < n_updates; i++) { - FreePool(updates[i]->name); - FreePool(updates[i]->info); - FreePool(updates[i]); - } - return ret; } static EFI_STATUS -search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) +fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) { EFI_DEVICE_PATH *dp, *parent_dp; EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID dpp = DEVICE_PATH_PROTOCOL; EFI_FILE_HANDLE *devices; - UINTN i, n_handles, count; + UINTN n_handles, count; EFI_STATUS rc; rc = uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &sfsp, NULL, &n_handles, (EFI_HANDLE **)&devices); if (EFI_ERROR(rc)) { - print(L"Could not find handles.\n"); + fwup_warning(L"Could not find handles"); return rc; } dp = *file_dp; - if (debugging) - print(L"Searching Device Path: %s ...\n", DevicePathToStr(dp)); - + fwup_debug(L"Searching Device Path: %s...", DevicePathToStr(dp)); parent_dp = DuplicateDevicePath(dp); - if (!parent_dp) { + if (parent_dp == NULL) { rc = EFI_INVALID_PARAMETER; goto out; } @@ -603,39 +222,32 @@ search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) } SetDevicePathEndNode(dp); + fwup_debug(L"Device Path prepared: %s", DevicePathToStr(parent_dp)); - if (debugging) - print(L"Device Path prepared: %s\n", - DevicePathToStr(parent_dp)); - - for (i = 0; i < n_handles; i++) { + for (UINTN i = 0; i < n_handles; i++) { EFI_DEVICE_PATH *path; rc = uefi_call_wrapper(BS->HandleProtocol, 3, devices[i], &dpp, - (void **)&path); + (VOID **)&path); if (EFI_ERROR(rc)) continue; - if (debugging) - print(L"Device supporting SFSP: %s\n", - DevicePathToStr(path)); + fwup_debug(L"Device supporting SFSP: %s", DevicePathToStr(path)); rc = EFI_UNSUPPORTED; while (!IsDevicePathEnd(path)) { - if (debugging) - print(L"Comparing: %s and %s\n", - DevicePathToStr(parent_dp), - DevicePathToStr(path)); + fwup_debug(L"Comparing: %s and %s", + DevicePathToStr(parent_dp), + DevicePathToStr(path)); if (LibMatchDevicePaths(path, parent_dp) == TRUE) { *fh = devices[i]; - for (i = 0; i < count; i++) + for (UINTN j = 0; j < count; j++) *file_dp = NextDevicePathNode(*file_dp); rc = EFI_SUCCESS; - if (debugging) - print(L"Match up! Returning %s\n", - DevicePathToStr(*file_dp)); + fwup_debug(L"Match up! Returning %s", + DevicePathToStr(*file_dp)); goto out; } @@ -646,14 +258,14 @@ search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) out: if (!EFI_ERROR(rc)) - print(L"File %s searched\n", DevicePathToStr(*file_dp)); + fwup_info(L"File %s searched", DevicePathToStr(*file_dp)); uefi_call_wrapper(BS->FreePool, 1, devices); return rc; } static EFI_STATUS -open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) +fwup_open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) { EFI_DEVICE_PATH *file_dp = dp; EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; @@ -665,16 +277,16 @@ open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) rc = uefi_call_wrapper(BS->LocateDevicePath, 3, &sfsp, &file_dp, (EFI_HANDLE *)&device); if (EFI_ERROR(rc)) { - rc = search_file(&file_dp, &device); + rc = fwup_search_file(&file_dp, &device); if (EFI_ERROR(rc)) { - print(L"Could not locate device handle: %r\n", rc); + fwup_warning(L"Could not locate device handle: %r", rc); return rc; } } if (DevicePathType(file_dp) != MEDIA_DEVICE_PATH || - DevicePathSubType(file_dp) != MEDIA_FILEPATH_DP) { - print(L"Could not find appropriate device.\n"); + DevicePathSubType(file_dp) != MEDIA_FILEPATH_DP) { + fwup_warning(L"Could not find appropriate device"); return EFI_UNSUPPORTED; } @@ -684,79 +296,70 @@ open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) sz = sz16; sz -= 4; if (sz <= 6 || sz % 2 != 0) { - print(L"Invalid file device path.\n"); + fwup_warning(L"Invalid file device path"); return EFI_INVALID_PARAMETER; } - sz /= sizeof (CHAR16); - /* - * check against some arbitrary limit to avoid having a stack - * overflow here. - */ + /*check against some arbitrary limit to avoid stack overflow here */ + sz /= sizeof(CHAR16); if (sz > 1024) { - print(L"Invalid file device path.\n"); + fwup_warning(L"Invalid file device path"); return EFI_INVALID_PARAMETER; } CHAR16 filename[sz+1]; - CopyMem(filename, (UINT8 *)file_dp + 4, sz * sizeof (CHAR16)); + CopyMem(filename, (UINT8 *)file_dp + 4, sz * sizeof(CHAR16)); filename[sz] = L'\0'; rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, &sfsp, - (void **)&drive); + (VOID **)&drive); if (EFI_ERROR(rc)) { - print(L"Could not open device interface: %r.\n", rc); + fwup_warning(L"Could not open device interface: %r", rc); return rc; } - dprint(L"Found device\n"); + fwup_debug(L"Found device"); rc = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); if (EFI_ERROR(rc)) { - print(L"Could not open volume: %r.\n", rc); + fwup_warning(L"Could not open volume: %r", rc); return rc; } - dprint(L"Found volume\n"); + fwup_debug(L"Found volume"); rc = uefi_call_wrapper(root->Open, 5, root, fh, filename, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(rc)) { - print(L"Could not open file \"%s\": %r.\n", filename, rc); + fwup_warning(L"Could not open file '%s': %r", filename, rc); return rc; } - dprint(L"Found file\n"); + fwup_debug(L"Found file"); return EFI_SUCCESS; } static EFI_STATUS -delete_boot_order(CHAR16 *name, EFI_GUID guid) +fwup_delete_boot_order(CHAR16 *name, EFI_GUID guid) { - - UINTN i; UINT16 boot_num; EFI_STATUS rc; UINTN info_size = 0; - UINT32 attributes = 0; - _cleanup_FreePool void *info_ptr = NULL; - _cleanup_FreePool UINT16 *new_info_ptr = NULL; - BOOLEAN num_found = FALSE; + UINT32 attrs = 0; + _cleanup_free VOID *info_ptr = NULL; + _cleanup_free UINT16 *new_info_ptr = NULL; + UINT8 num_found = FALSE; UINTN new_list_num = 0; /* get boot hex number */ boot_num = xtoi((CHAR16 *)((UINT8 *)name + sizeof(L"Boot"))); - rc = read_variable(L"BootOrder", guid, &info_ptr, &info_size, - &attributes); + rc = fwup_get_variable(L"BootOrder", &guid, &info_ptr, &info_size, &attrs); if (EFI_ERROR(rc)) return rc; - new_info_ptr = AllocatePool(info_size); - if (!new_info_ptr) { - print(L"Tried to allocate %d\n", info_size); - print(L"Could not allocate memory.\n"); + new_info_ptr = fwup_malloc(info_size); + if (new_info_ptr == NULL) return EFI_OUT_OF_RESOURCES; - } - for (i = 0; i < (info_size / sizeof(UINT16)) ; i++) { + for (UINTN i = 0; i < (info_size / sizeof(UINT16)) ; i++) { if (((UINT16 *)info_ptr)[i] != boot_num) { new_info_ptr[i] = ((UINT16 *)info_ptr)[i]; new_list_num++; @@ -771,112 +374,82 @@ delete_boot_order(CHAR16 *name, EFI_GUID guid) return EFI_SUCCESS; rc = uefi_call_wrapper(RT->SetVariable, 5, L"BootOrder", &guid, - attributes, new_list_num * sizeof(UINT16), + attrs, new_list_num * sizeof(UINT16), new_info_ptr); if (EFI_ERROR(rc)) { - print(L"Could not update variable status for \"%s\": %r\n", - name, rc); + fwup_warning(L"Could not update variable status for '%s': %r", + name, rc); return rc; } return rc; } static EFI_STATUS -delete_boot_entry(void) +fwup_delete_boot_entry(VOID) { EFI_STATUS rc; - - UINTN variable_name_allocation = GNVN_BUF_SIZE; UINTN variable_name_size = 0; - _cleanup_FreePool CHAR16 *variable_name = NULL; + _cleanup_free CHAR16 *variable_name = NULL; EFI_GUID vendor_guid = empty_guid; - UINTN mult_res; - variable_name = AllocateZeroPool(GNVN_BUF_SIZE * 2); - if (!variable_name) { - print(L"Tried to allocate %d\n", GNVN_BUF_SIZE * 2); - print(L"Could not allocate memory.\n"); + variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); + if (variable_name == NULL) return EFI_OUT_OF_RESOURCES; - } while (1) { - variable_name_size = variable_name_allocation; + variable_name_size = GNVN_BUF_SIZE; rc = uefi_call_wrapper(RT->GetNextVariableName, 3, &variable_name_size, variable_name, &vendor_guid); - if (rc == EFI_BUFFER_TOO_SMALL) { - - UINTN new_allocation; - CHAR16 *new_name; - - new_allocation = variable_name_size; - if (uintn_mult(new_allocation, 2, &mult_res)) { - print(L"%d * 2 would overflow size\n", - new_allocation); - return EFI_OUT_OF_RESOURCES; - } - new_name = AllocatePool(new_allocation * 2); - if (!new_name) { - print(L"Tried to allocate %d\n", - new_allocation * 2); - print(L"Could not allocate memory.\n"); - return EFI_OUT_OF_RESOURCES; - } - CopyMem(new_name, variable_name, - variable_name_allocation); - variable_name_allocation = new_allocation; - FreePool(variable_name); - variable_name = new_name; - continue; - } else if (rc == EFI_NOT_FOUND) { + if (rc == EFI_NOT_FOUND) break; - } else if (EFI_ERROR(rc)) { - print(L"Could not get variable name: %r\n", rc); + /* ignore any huge names */ + if (rc == EFI_BUFFER_TOO_SMALL) + continue; + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable name: %r", rc); return rc; } /* check if the variable name is Boot#### */ - UINTN vns = StrLen(variable_name); - if (!guid_cmp(&vendor_guid, &global_variable_guid) - && vns == 8 && CompareMem(variable_name, L"Boot", 8) == 0) { - UINTN info_size = 0; - UINT32 attributes = 0; - _cleanup_FreePool void *info_ptr = NULL; - CHAR16 *load_op_description = NULL; - CHAR16 target[] = L"Linux Firmware Updater"; + if (CompareGuid(&vendor_guid, &global_variable_guid) != 0) + continue; + if (StrCmp(variable_name, L"Boot") != 0) + continue; - rc = read_variable(variable_name, vendor_guid, - &info_ptr, &info_size, &attributes); - if (EFI_ERROR(rc)) + UINTN info_size = 0; + UINT32 attrs = 0; + _cleanup_free VOID *info_ptr = NULL; + + /* get the data */ + rc = fwup_get_variable(variable_name, &vendor_guid, + &info_ptr, &info_size, &attrs); + if (EFI_ERROR(rc)) + return rc; + if (info_size < sizeof(EFI_LOAD_OPTION)) + continue; + + CHAR16 target[] = L"Linux Firmware Updater"; + /* + * check if the boot path created by fwupdate, + * check with EFI_LOAD_OPTION decription + */ + EFI_LOAD_OPTION *load_op = (EFI_LOAD_OPTION *) info_ptr; + if (CompareMem(load_op->description, target, + sizeof(target) - 2) == 0) { + /* delete the boot path from BootOrder list */ + rc = fwup_delete_boot_order(variable_name, vendor_guid); + if (EFI_ERROR(rc)) { + fwup_warning(L"Failed to delete boot entry from BootOrder"); return rc; - - /* - * check if the boot path created by fwupdate, - * check with EFI_LOAD_OPTION decription - */ - load_op_description = (CHAR16 *) - ((UINT8 *)info_ptr - + sizeof(UINT32) - + sizeof(UINT16)); - - if (CompareMem(load_op_description, target, - sizeof(target) - 2) == 0) { - /* delete the boot path from BootOrder list */ - rc = delete_boot_order(variable_name, - vendor_guid); - if (EFI_ERROR(rc)) { - print(L"Failed to delete the Linux Firmware Updater boot entry from BootOrder.\n"); - return rc; - } - - rc = delete_variable(variable_name, - vendor_guid, attributes); - if (EFI_ERROR(rc)) { - print(L"Failed to delete the Linux Firmware Updater boot entry.\n"); - return rc; - } - break; } + rc = fwup_delete_variable(variable_name, + &vendor_guid, attrs); + if (EFI_ERROR(rc)) { + fwup_warning(L"Failed to delete boot entry"); + return rc; + } + break; } } @@ -884,24 +457,24 @@ delete_boot_entry(void) } static EFI_STATUS -get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) +fwup_get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) { EFI_HANDLE *handles, gop_handle; - UINTN num_handles, i; + UINTN num_handles; EFI_STATUS status; EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; - void *iface; + VOID *iface; status = LibLocateHandle(ByProtocol, &gop_guid, NULL, &num_handles, &handles); if (EFI_ERROR(status)) return status; - if (!handles || num_handles == 0) + if (handles == NULL || num_handles == 0) return EFI_UNSUPPORTED; - for (i = 0; i < num_handles; i++) { + for (UINTN i = 0; i < num_handles; i++) { gop_handle = handles[i]; status = uefi_call_wrapper(BS->OpenProtocol, 6, @@ -921,31 +494,23 @@ get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) } static EFI_STATUS -do_ux_csum(EFI_HANDLE loaded_image, UINT8 *buf, UINTN size) +fwup_check_gop_for_ux_capsule(EFI_HANDLE loaded_image, + EFI_CAPSULE_HEADER *capsule) { - ux_capsule_header_t *payload_hdr; - EFI_CAPSULE_HEADER *capsule; + UX_CAPSULE_HEADER *payload_hdr; EFI_STATUS rc; - if (size < sizeof(*capsule)) { - dprint(L"Invalid capsule size %d\n", size); - return EFI_INVALID_PARAMETER; - } - - capsule = (EFI_CAPSULE_HEADER *)buf; - payload_hdr = (ux_capsule_header_t *)(buf) + capsule->HeaderSize; - rc = get_gop_mode(&payload_hdr->mode, loaded_image); + payload_hdr = (UX_CAPSULE_HEADER *)((UINT8*) capsule) + capsule->HeaderSize; + rc = fwup_get_gop_mode(&payload_hdr->mode, loaded_image); if (EFI_ERROR(rc)) return EFI_UNSUPPORTED; return EFI_SUCCESS; } -#define is_ux_capsule(guid) (guid_cmp(guid, &ux_capsule_guid) == 0) - static EFI_STATUS -add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out, - EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_out, EFI_HANDLE loaded_image) +fwup_add_update_capsule(FWUP_UPDATE_TABLE *update, EFI_CAPSULE_HEADER **capsule_out, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_out, EFI_HANDLE loaded_image) { EFI_STATUS rc; EFI_FILE_HANDLE fh = NULL; @@ -957,24 +522,30 @@ add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out, EFI_PHYSICAL_ADDRESS cbd_data; EFI_CAPSULE_HEADER *cap_out; - rc = open_file((EFI_DEVICE_PATH *)update->info->dp_buf, &fh); + rc = fwup_open_file((EFI_DEVICE_PATH *)update->info->dp_buf, &fh); if (EFI_ERROR(rc)) return rc; - rc = read_file(fh, &fbuf, &fsize); + rc = fwup_read_file(fh, &fbuf, &fsize); if (EFI_ERROR(rc)) return rc; uefi_call_wrapper(fh->Close, 1, fh); - dprint(L"Read file; %d bytes\n", fsize); - dprint(L"updates guid: %g\n", &update->info->guid); - dprint(L"File guid: %g\n", fbuf); + if (fsize < sizeof(EFI_CAPSULE_HEADER)) { + fwup_warning(L"Invalid capsule size %d", fsize); + return EFI_INVALID_PARAMETER; + } + + fwup_debug(L"Read file; %d bytes", fsize); + fwup_debug(L"updates guid: %g", &update->info->guid); + fwup_debug(L"File guid: %g", fbuf); cbd_len = fsize; cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; - if (!cap_out->Flags && !is_ux_capsule(&update->info->guid)) { + if (cap_out->Flags == 0 && + CompareGuid(&update->info->guid, &ux_capsule_guid) != 0) { #if defined(__aarch64__) cap_out->Flags |= update->info->capsule_flags; #else @@ -984,9 +555,9 @@ add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out, #endif } - if (is_ux_capsule(&update->info->guid)) { - dprint(L"Checksumming ux capsule\n"); - rc = do_ux_csum(loaded_image, (UINT8 *)capsule, cbd_len); + if (CompareGuid(&update->info->guid, &ux_capsule_guid) == 0) { + fwup_debug(L"Checking GOP for ux capsule"); + rc = fwup_check_gop_for_ux_capsule(loaded_image, capsule); if (EFI_ERROR(rc)) return EFI_UNSUPPORTED; } @@ -998,54 +569,49 @@ add_capsule(update_table *update, EFI_CAPSULE_HEADER **capsule_out, return EFI_SUCCESS; } - static EFI_STATUS -apply_capsules(EFI_CAPSULE_HEADER **capsules, - EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd, - UINTN num_updates, EFI_RESET_TYPE *reset) +fwup_apply_capsules(EFI_CAPSULE_HEADER **capsules, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd, + UINTN num_updates, EFI_RESET_TYPE *reset) { UINT64 max_capsule_size; EFI_STATUS rc; - rc = delete_boot_entry(); - if (EFI_ERROR(rc)) { - /* - * Print out deleting boot entry error, but still try to apply - * capsule. - */ - dprint(L"Could not delete boot entry: %r\n", - __FILE__, __func__, __LINE__, rc); - } + /* still try to apply capsule on failure */ + rc = fwup_delete_boot_entry(); + if (EFI_ERROR(rc)) + fwup_warning(L"Could not delete boot entry: %r", rc); rc = uefi_call_wrapper(RT->QueryCapsuleCapabilities, 4, capsules, num_updates, &max_capsule_size, reset); - dprint(L"QueryCapsuleCapabilities: %r max: %ld reset:%d\n", - rc, max_capsule_size, *reset); - dprint(L"Capsules: %d\n", num_updates); + fwup_debug(L"QueryCapsuleCapabilities: %r max: %ld reset:%d", + rc, max_capsule_size, *reset); + fwup_debug(L"Capsules: %d", num_updates); - uefi_call_wrapper(BS->Stall, 1, 1 * SECONDS); + fwup_msleep(1 * SECONDS); rc = uefi_call_wrapper(RT->UpdateCapsule, 3, capsules, num_updates, (EFI_PHYSICAL_ADDRESS)(UINTN)cbd); if (EFI_ERROR(rc)) { - print(L"Could not apply capsule update: %r\n", rc); + fwup_warning(L"Could not apply capsule update: %r", rc); return rc; } return EFI_SUCCESS; } -static -EFI_STATUS -set_statuses(UINTN n_updates, update_table **updates) +static EFI_STATUS +fwup_set_update_statuses(FWUP_UPDATE_TABLE **updates) { EFI_STATUS rc; - for (UINTN i = 0; i < n_updates; i++) { - rc = uefi_call_wrapper(RT->SetVariable, 5, updates[i]->name, - &fwupdate_guid, updates[i]->attributes, - updates[i]->size, updates[i]->info); + for (UINTN i = 0; i < FWUP_NUM_CAPSULE_UPDATES_MAX; i++) { + if (updates[i]->name == NULL) + break; + rc = fwup_set_variable(updates[i]->name, &fwupdate_guid, + updates[i]->info, updates[i]->size, + updates[i]->attrs); if (EFI_ERROR(rc)) { - print(L"Coould not update variable status for \"%s\": %r\n", - updates[i]->name, rc); + fwup_warning(L"Could not update variable status for '%s': %r", + updates[i]->name, rc); return rc; } } @@ -1055,75 +621,56 @@ set_statuses(UINTN n_updates, update_table **updates) EFI_GUID SHIM_LOCK_GUID = {0x605dab50,0xe046,0x4300,{0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23}}; -static void +static VOID __attribute__((__optimize__("0"))) -debug_hook(void) +fwup_debug_hook(VOID) { EFI_GUID guid = SHIM_LOCK_GUID; UINTN data = 0; UINTN data_size = 1; EFI_STATUS efi_status; - UINT32 attributes; + UINT32 attrs; register volatile int x = 0; extern char _text UNUSED, _data UNUSED; - /* - * If SHIM_DEBUG is set, we're going to assume shim has done whatever - * is needed to get a debugger attached, and we just need to explain - * who and where we are, and also enable our debugging output. - */ + /* shim has done whatever is needed to get a debugger attached */ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SHIM_DEBUG", - &guid, &attributes, &data_size, &data); + &guid, &attrs, &data_size, &data); if (EFI_ERROR(efi_status) || data != 1) { efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"FWUPDATE_VERBOSE", - &fwupdate_guid, &attributes, + &fwupdate_guid, &attrs, &data_size, &data); - if (EFI_ERROR(efi_status) || data != 1) { + if (EFI_ERROR(efi_status) || data != 1) return; - } - debugging = 1; + fwup_debug_set_enabled(TRUE); return; } - debugging = 1; + fwup_debug_set_enabled(TRUE); if (x) return; x = 1; - print(L"add-symbol-file "DEBUGDIR - L"fwupdate.efi.debug %p -s .data %p\n", - &_text, &_data); + fwup_info(L"add-symbol-file "DEBUGDIR + L"fwupdate.efi.debug %p -s .data %p", + &_text, &_data); } EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { EFI_STATUS rc; - update_table **updates = NULL; - UINTN n_updates = 0; + UINTN i, n_updates = 0; EFI_RESET_TYPE reset_type = EfiResetWarm; + _cleanup_free FWUP_UPDATE_TABLE **updates = NULL; InitializeLib(image, systab); - /* - * if SHIM_DEBUG is set, print info for our attached debugger. - */ - debug_hook(); + /* if SHIM_DEBUG is set, fwup_info info for our attached debugger */ + fwup_debug_hook(); - /* - * Basically the workflow here is: - * 1) find and validate any update state variables with the right GUID - * 2) allocate our capsule data structures and add the capsules - * #1 described - * 3) update status variables - * 4) apply the capsule updates - * 5) reboot - */ - - /* - * Step 1: find and validate update state variables - */ + /* step 1: find and validate update state variables */ /* XXX TODO: * 1) survey the reset types first, and separate into groups * according to them @@ -1131,78 +678,65 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) * so we can do multiple runs * 3) only select the ones from one type for the first go */ - rc = find_updates(&n_updates, &updates); + updates = fwup_malloc0(FWUP_NUM_CAPSULE_UPDATES_MAX); + if (updates == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_table(updates, &n_updates); if (EFI_ERROR(rc)) { - print(L"fwupdate: Could not find updates: %r\n", rc); + fwup_warning(L"Could not find updates: %r", rc); return rc; } if (n_updates == 0) { - print(L"fwupdate: No updates to process. Called in error?\n"); + fwup_warning(L"No updates to process. Called in error?"); return EFI_INVALID_PARAMETER; } - /* - * Step 2: Build our data structure and add the capsules to it. - */ + /* step 2: Build our data structure and add the capsules to it */ EFI_CAPSULE_HEADER *capsules[n_updates + 1]; EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_data; - UINTN i, j; - rc = allocate((void **)&cbd_data, - sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); - if (EFI_ERROR(rc)) { - print(L"Tried to allocate %d\n", - sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); - print(L"fwupdate: Could not allocate memory: %r.\n",rc); - return rc; - } - for (i = 0, j = 0; i < n_updates; i++) { - dprint(L"Adding new capsule\n"); - rc = add_capsule(updates[i], &capsules[j], &cbd_data[j], - image); + UINTN j = 0; + cbd_data = fwup_malloc_raw(sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); + if (cbd_data == NULL) + return EFI_OUT_OF_RESOURCES; + for (i = 0; i < n_updates; i++) { + fwup_info(L"Adding new capsule"); + rc = fwup_add_update_capsule(updates[i], &capsules[j], &cbd_data[j], image); if (EFI_ERROR(rc)) { + /* ignore a failing UX capsule */ if (rc == EFI_UNSUPPORTED && - is_ux_capsule(&updates[i]->info->guid)) + CompareGuid(&updates[i]->info->guid, &ux_capsule_guid) == 0) continue; - dprint(L"fwupdate: Could not build update list: %r\n", - rc); + fwup_warning(L"Could not build update list: %r", rc); return rc; } j++; } n_updates = j; - dprint(L"n_updates: %d\n", n_updates); + fwup_debug(L"n_updates: %d", n_updates); cbd_data[i].Length = 0; cbd_data[i].Union.ContinuationPointer = 0; - /* - * Step 3: update the state variables. - */ - rc = set_statuses(n_updates, updates); + /* step 3: update the state variables */ + rc = fwup_set_update_statuses(updates); if (EFI_ERROR(rc)) { - print(L"fwupdate: Could not set update status: %r\n", rc); + fwup_warning(L"Could not set update status: %r", rc); return rc; } - /* - * Step 4: apply the capsules. - */ - rc = apply_capsules(capsules, cbd_data, n_updates, &reset_type); + /* step 4: apply the capsules */ + rc = fwup_apply_capsules(capsules, cbd_data, n_updates, &reset_type); if (EFI_ERROR(rc)) { - print(L"fwupdate: Could not apply capsules: %r\n", rc); + fwup_warning(L"Could not apply capsules: %r", rc); return rc; } - /* - * Step 5: if #4 didn't reboot us, do it manually. - */ - dprint(L"fwupdate: Reset System\n"); - if (debugging) - uefi_call_wrapper(BS->Stall, 1, 5 * SECONDS); - - uefi_call_wrapper(BS->Stall, 1, 5 * SECONDS); - uefi_call_wrapper(RT->ResetSystem, 4, reset_type, EFI_SUCCESS, - 0, NULL); + /* step 5: if #4 didn't reboot us, do it manually */ + fwup_info(L"Reset System"); + fwup_msleep(5 * SECONDS); + if (fwup_debug_get_enabled()) + fwup_msleep(30 * SECONDS); + uefi_call_wrapper(RT->ResetSystem, 4, reset_type, EFI_SUCCESS, 0, NULL); return EFI_SUCCESS; } diff --git a/plugins/uefi/efi/meson.build b/plugins/uefi/efi/meson.build index d78aab99a..851b6d92b 100644 --- a/plugins/uefi/efi/meson.build +++ b/plugins/uefi/efi/meson.build @@ -103,14 +103,29 @@ endif libgcc_file_name = run_command(efi_cc, '-print-libgcc-file-name').stdout().strip() efi_name = 'fwupd@0@.efi'.format(EFI_MACHINE_TYPE_NAME) -o_file = custom_target('fwupdate.o', +o_file1 = custom_target('fwupdate.o', input : 'fwupdate.c', output : 'fwupdate.o', command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + compile_args) +o_file2 = custom_target('fwup-debug.o', + input : 'fwup-debug.c', + output : 'fwup-debug.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file3 = custom_target('fwup-efi.o', + input : 'fwup-efi.c', + output : 'fwup-efi.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file4 = custom_target('fwup-common.o', + input : 'fwup-common.c', + output : 'fwup-common.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) so = custom_target('fwup.so', - input : o_file, + input : [o_file1, o_file2, o_file3, o_file4], output : 'fwup.so', command : [efi_ld, '-o', '@OUTPUT@'] + efi_ldflags + ['@INPUT@'] + From 37b985c156edf2f3ecbd404ced3152ad1c75dd58 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Sun, 20 Jan 2019 11:23:32 +0100 Subject: [PATCH 188/254] Check if plugin changed after the device attaches or detaches If the device is rebooted into a different shape, the plugin managing the device may also be different. This would be the case for plugins that just subclass the update_detach() method, and leave to other plugins the actual required update procedure. --- src/fu-engine.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 8b7c2559a..a262e01d0 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1563,6 +1563,13 @@ fu_engine_install_blob (FuEngine *self, g_prefix_error (error, "failed to get device after detach: "); return FALSE; } + + /* get new plugin after detach */ + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; if (!fu_plugin_runner_update (plugin, device, blob_cab, @@ -1630,6 +1637,13 @@ fu_engine_install_blob (FuEngine *self, return FALSE; } + /* get new plugin after attach */ + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + /* get the new version number */ if (!fu_plugin_runner_update_reload (plugin, device, error)) { g_prefix_error (error, "failed to reload device: "); From 525433e4de38ab06145714c9c6889f6e2bf67dc8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 20 Jan 2019 08:16:29 +0000 Subject: [PATCH 189/254] uefi: Use the GNU-EFI BOOL type --- plugins/uefi/efi/fwup-debug.c | 8 ++++---- plugins/uefi/efi/fwup-debug.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/uefi/efi/fwup-debug.c b/plugins/uefi/efi/fwup-debug.c index c5c3f5636..0f72ac045 100644 --- a/plugins/uefi/efi/fwup-debug.c +++ b/plugins/uefi/efi/fwup-debug.c @@ -11,16 +11,16 @@ #include "fwup-debug.h" #include "fwup-efi.h" -static UINT8 debugging = FALSE; +static BOOLEAN debugging = FALSE; -UINT8 +BOOLEAN fwup_debug_get_enabled(VOID) { return debugging; } VOID -fwup_debug_set_enabled(UINT8 val) +fwup_debug_set_enabled(BOOLEAN val) { debugging = val; } @@ -32,7 +32,7 @@ fwupd_debug_efivar_append(CHAR16 *out1) UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; - static UINT8 once = TRUE; + static BOOLEAN once = TRUE; if (once) { once = FALSE; fwup_delete_variable(name, &fwupdate_guid, attrs); diff --git a/plugins/uefi/efi/fwup-debug.h b/plugins/uefi/efi/fwup-debug.h index 39b72c800..1e1de2198 100644 --- a/plugins/uefi/efi/fwup-debug.h +++ b/plugins/uefi/efi/fwup-debug.h @@ -22,8 +22,8 @@ VOID fwup_log (FwupLogLevel level, CHAR16 *fmt, ...); -UINT8 fwup_debug_get_enabled (VOID); -VOID fwup_debug_set_enabled (UINT8 val); +BOOLEAN fwup_debug_get_enabled (VOID); +VOID fwup_debug_set_enabled (BOOLEAN val); #define fwup_debug(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_DEBUG, __func__, __FILE__, __LINE__, fmt, ## args ) #define fwup_info(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_INFO, __func__, __FILE__, __LINE__, fmt, ## args ) From aa6498866ce4d1dd8068f359fd5dabbe343d394c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 17 Jan 2019 16:35:14 +0000 Subject: [PATCH 190/254] uefi: Delete the old Linux-Firmware-Updater boot entry --- plugins/uefi/efi/fwupdate.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index 8645b11ce..143593384 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -384,6 +384,19 @@ fwup_delete_boot_order(CHAR16 *name, EFI_GUID guid) return rc; } +/* TODO: move to gnu-efi: https://github.com/vathpela/gnu-efi/issues/7 */ +static BOOLEAN +_StrHasPrefix(IN CONST CHAR16 *s1, IN CONST CHAR16 *s2) +{ + while (*s2) { + if (*s1 == L'\0' || *s1 != *s2) + return FALSE; + s1 += 1; + s2 += 1; + } + return TRUE; +} + static EFI_STATUS fwup_delete_boot_entry(VOID) { @@ -429,14 +442,13 @@ fwup_delete_boot_entry(VOID) if (info_size < sizeof(EFI_LOAD_OPTION)) continue; - CHAR16 target[] = L"Linux Firmware Updater"; /* * check if the boot path created by fwupdate, * check with EFI_LOAD_OPTION decription */ EFI_LOAD_OPTION *load_op = (EFI_LOAD_OPTION *) info_ptr; - if (CompareMem(load_op->description, target, - sizeof(target) - 2) == 0) { + if (_StrHasPrefix(load_op->description, L"Linux Firmware Updater") || + _StrHasPrefix(load_op->description, L"Linux-Firmware-Updater")) { /* delete the boot path from BootOrder list */ rc = fwup_delete_boot_order(variable_name, vendor_guid); if (EFI_ERROR(rc)) { From 00b87884c4bff63f0bb95547e32b42937e308f53 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 20 Jan 2019 08:33:30 +0000 Subject: [PATCH 191/254] uefi: Do not pass required attrs to fwup_delete_variable() This lets us refactor some code and remove some complexity. --- plugins/uefi/efi/fwup-debug.c | 2 +- plugins/uefi/efi/fwup-efi.c | 15 ++++++++++++++- plugins/uefi/efi/fwup-efi.h | 3 +-- plugins/uefi/efi/fwupdate.c | 11 +++-------- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/plugins/uefi/efi/fwup-debug.c b/plugins/uefi/efi/fwup-debug.c index 0f72ac045..bbb2d0198 100644 --- a/plugins/uefi/efi/fwup-debug.c +++ b/plugins/uefi/efi/fwup-debug.c @@ -35,7 +35,7 @@ fwupd_debug_efivar_append(CHAR16 *out1) static BOOLEAN once = TRUE; if (once) { once = FALSE; - fwup_delete_variable(name, &fwupdate_guid, attrs); + fwup_delete_variable(name, &fwupdate_guid); } else { attrs |= EFI_VARIABLE_APPEND_WRITE; } diff --git a/plugins/uefi/efi/fwup-efi.c b/plugins/uefi/efi/fwup-efi.c index 05e7fa196..8da6b2021 100644 --- a/plugins/uefi/efi/fwup-efi.c +++ b/plugins/uefi/efi/fwup-efi.c @@ -13,8 +13,21 @@ #include "fwup-efi.h" EFI_STATUS -fwup_delete_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs) +fwup_delete_variable(CHAR16 *name, EFI_GUID *guid) { + EFI_STATUS rc; + UINT32 attrs = 0; + + /* get the attrs so we can delete it */ + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, NULL, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_NOT_FOUND) { + fwup_debug(L"Not deleting variable '%s' as not found", name); + return EFI_SUCCESS; + } + fwup_debug(L"Could not get variable '%s' for delete: %r", name, rc); + return rc; + } return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, 0, NULL); } diff --git a/plugins/uefi/efi/fwup-efi.h b/plugins/uefi/efi/fwup-efi.h index f7b43b2da..bb2a8092e 100644 --- a/plugins/uefi/efi/fwup-efi.h +++ b/plugins/uefi/efi/fwup-efi.h @@ -57,8 +57,7 @@ typedef struct { } __attribute__((__packed__)) EFI_LOAD_OPTION; EFI_STATUS fwup_delete_variable (CHAR16 *name, - EFI_GUID *guid, - UINT32 attrs); + EFI_GUID *guid); EFI_STATUS fwup_set_variable (CHAR16 *name, EFI_GUID *guid, VOID *data, diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index 143593384..7b294a449 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -72,14 +72,12 @@ fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) if (info_size < sizeof(*info)) { fwup_warning(L"Update '%s' is is too small", name); - fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } if (info_size - sizeof(EFI_DEVICE_PATH) <= sizeof(*info)) { fwup_warning(L"Update '%s' is malformed, " L"and cannot hold a file path", name); - fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } @@ -89,7 +87,6 @@ fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) fwup_warning(L"Update '%s' has an invalid file path, " L"device path offset is %d, but total size is %d", name, is, info_size); - fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } @@ -99,7 +96,6 @@ fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) fwup_warning(L"Update '%s' has an invalid file path, " L"update info size: %d dp size: %d size for dp: %d", name, info_size, sz, is); - fwup_delete_variable(name, &fwupdate_guid, attrs); return EFI_INVALID_PARAMETER; } @@ -165,6 +161,7 @@ fwup_populate_update_table(FWUP_UPDATE_TABLE **updates, UINTN *n_updates_out) return EFI_OUT_OF_RESOURCES; rc = fwup_populate_update_info(variable_name, update); if (EFI_ERROR(rc)) { + fwup_delete_variable(variable_name, &fwupdate_guid); fwup_warning(L"Could not populate update info for '%s'", variable_name); return rc; } @@ -431,12 +428,11 @@ fwup_delete_boot_entry(VOID) continue; UINTN info_size = 0; - UINT32 attrs = 0; _cleanup_free VOID *info_ptr = NULL; /* get the data */ rc = fwup_get_variable(variable_name, &vendor_guid, - &info_ptr, &info_size, &attrs); + &info_ptr, &info_size, NULL); if (EFI_ERROR(rc)) return rc; if (info_size < sizeof(EFI_LOAD_OPTION)) @@ -455,8 +451,7 @@ fwup_delete_boot_entry(VOID) fwup_warning(L"Failed to delete boot entry from BootOrder"); return rc; } - rc = fwup_delete_variable(variable_name, - &vendor_guid, attrs); + rc = fwup_delete_variable(variable_name, &vendor_guid); if (EFI_ERROR(rc)) { fwup_warning(L"Failed to delete boot entry"); return rc; From 59407ca42da84b1d439f3882b1ec1d6b8e17e960 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 20 Jan 2019 08:49:31 +0000 Subject: [PATCH 192/254] uefi: Use _cleanup_free in one more place --- plugins/uefi/efi/fwupdate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index 7b294a449..a53e5c254 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -182,9 +182,9 @@ fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) EFI_DEVICE_PATH *dp, *parent_dp; EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_GUID dpp = DEVICE_PATH_PROTOCOL; - EFI_FILE_HANDLE *devices; UINTN n_handles, count; EFI_STATUS rc; + _cleanup_free EFI_FILE_HANDLE *devices = NULL; rc = uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &sfsp, NULL, &n_handles, (EFI_HANDLE **)&devices); @@ -257,7 +257,6 @@ out: if (!EFI_ERROR(rc)) fwup_info(L"File %s searched", DevicePathToStr(*file_dp)); - uefi_call_wrapper(BS->FreePool, 1, devices); return rc; } From 31c10b72938372cf3ce22cab8744b426f4dd3a37 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 20 Jan 2019 08:51:35 +0000 Subject: [PATCH 193/254] uefi: Fix a logic bug in fwup_search_file() If n_handles==0 then we'd return with EFI_SUCCESS, rather than failure. --- plugins/uefi/efi/fwupdate.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index a53e5c254..ae0dd7a23 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -197,18 +197,14 @@ fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) fwup_debug(L"Searching Device Path: %s...", DevicePathToStr(dp)); parent_dp = DuplicateDevicePath(dp); - if (parent_dp == NULL) { - rc = EFI_INVALID_PARAMETER; - goto out; - } + if (parent_dp == NULL) + return EFI_INVALID_PARAMETER; dp = parent_dp; count = 0; while (1) { - if (IsDevicePathEnd(dp)) { - rc = EFI_INVALID_PARAMETER; - goto out; - } + if (IsDevicePathEnd(dp)) + return EFI_INVALID_PARAMETER; if (DevicePathType(dp) == MEDIA_DEVICE_PATH && DevicePathSubType(dp) == MEDIA_FILEPATH_DP) @@ -231,7 +227,6 @@ fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) fwup_debug(L"Device supporting SFSP: %s", DevicePathToStr(path)); - rc = EFI_UNSUPPORTED; while (!IsDevicePathEnd(path)) { fwup_debug(L"Comparing: %s and %s", DevicePathToStr(parent_dp), @@ -241,23 +236,18 @@ fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) *fh = devices[i]; for (UINTN j = 0; j < count; j++) *file_dp = NextDevicePathNode(*file_dp); - rc = EFI_SUCCESS; fwup_debug(L"Match up! Returning %s", DevicePathToStr(*file_dp)); - - goto out; + return EFI_SUCCESS; } path = NextDevicePathNode(path); } } -out: - if (!EFI_ERROR(rc)) - fwup_info(L"File %s searched", DevicePathToStr(*file_dp)); - - return rc; + fwup_warning(L"Failed to find '%s' DevicePath", DevicePathToStr(*file_dp)); + return EFI_UNSUPPORTED; } static EFI_STATUS From c7327385f47f9951de419c393577dbf0a3b010b5 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 20 Jan 2019 09:12:03 +0000 Subject: [PATCH 194/254] uefi: Remove all variable length arrays --- plugins/uefi/efi/fwup-common.h | 3 +++ plugins/uefi/efi/fwupdate.c | 20 ++++++++------------ plugins/uefi/efi/meson.build | 1 + 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/uefi/efi/fwup-common.h b/plugins/uefi/efi/fwup-common.h index 9ea12e90c..9aee941c1 100644 --- a/plugins/uefi/efi/fwup-common.h +++ b/plugins/uefi/efi/fwup-common.h @@ -20,4 +20,7 @@ VOID *fwup_malloc_raw (UINTN size); VOID *fwup_malloc (UINTN size); VOID *fwup_malloc0 (UINTN size); +#define fwup_new(struct_type, n) ((struct_type*)fwup_malloc((n)*sizeof(struct_type))) +#define fwup_new0(struct_type, n) ((struct_type*)fwup_malloc0((n)*sizeof(struct_type))) + #endif /* _FWUP_COMMON_H */ diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index ae0dd7a23..5556bf77d 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -253,6 +253,7 @@ fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) static EFI_STATUS fwup_open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) { + CONST UINTN devpath_max_size = 1024; /* arbitrary limit */ EFI_DEVICE_PATH *file_dp = dp; EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; EFI_FILE_HANDLE device; @@ -281,20 +282,14 @@ fwup_open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) CopyMem(&sz16, &file_dp->Length[0], sizeof(sz16)); sz = sz16; sz -= 4; - if (sz <= 6 || sz % 2 != 0) { - fwup_warning(L"Invalid file device path"); + if (sz <= 6 || sz % 2 != 0 || + sz > devpath_max_size * sizeof(CHAR16)) { + fwup_warning(L"Invalid file device path of size %d", sz); return EFI_INVALID_PARAMETER; } - /*check against some arbitrary limit to avoid stack overflow here */ - sz /= sizeof(CHAR16); - if (sz > 1024) { - fwup_warning(L"Invalid file device path"); - return EFI_INVALID_PARAMETER; - } - CHAR16 filename[sz+1]; - CopyMem(filename, (UINT8 *)file_dp + 4, sz * sizeof(CHAR16)); - filename[sz] = L'\0'; + _cleanup_free CHAR16 *filename = fwup_malloc0(sz + sizeof(CHAR16)); + CopyMem(filename, (UINT8 *)file_dp + 4, sz); rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, &sfsp, (VOID **)&drive); @@ -688,7 +683,8 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) } /* step 2: Build our data structure and add the capsules to it */ - EFI_CAPSULE_HEADER *capsules[n_updates + 1]; + _cleanup_free EFI_CAPSULE_HEADER **capsules = NULL; + capsules = fwup_new0(EFI_CAPSULE_HEADER *, n_updates + 1); EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_data; UINTN j = 0; cbd_data = fwup_malloc_raw(sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); diff --git a/plugins/uefi/efi/meson.build b/plugins/uefi/efi/meson.build index 851b6d92b..dbccda03f 100644 --- a/plugins/uefi/efi/meson.build +++ b/plugins/uefi/efi/meson.build @@ -55,6 +55,7 @@ compile_args = ['-Og', '-Wall', '-Werror', '-Wextra', + '-Wvla', '-std=gnu11', '-fpic', '-fshort-wchar', From 088c258894f21835fb4211155d3b2f60b1b1884c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 20 Jan 2019 09:28:05 +0000 Subject: [PATCH 195/254] trivial: Make one uefi function static --- plugins/uefi/efi/fwupdate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index 5556bf77d..605b98fee 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -23,7 +23,7 @@ typedef struct { FWUP_UPDATE_INFO *info; } FWUP_UPDATE_TABLE; -VOID +static VOID fwup_update_table_free(FWUP_UPDATE_TABLE *update) { FreePool(update->info); From 68fb11f453f66d1cf48358992f19fc5af56cdc79 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 21 Jan 2019 22:52:22 -0600 Subject: [PATCH 196/254] uefi: Correct a boot order creation bug (Fixes: #956) Unfortunately the previous fix (6131f5d) introduced this bug. The code previously was actually looking for the non-zero case which was correct, but non-obvious since `efi_guid_cmp` works like `g_strcmp0` where a match returns zero. So rather than revert 6131f5d make this completly explicit. --- plugins/uefi/fu-uefi-bootmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index 7bec31178..76834dfe2 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -108,7 +108,7 @@ fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_si efidp found_dp; g_autofree guint8 *var_data_tmp = NULL; - if (efi_guid_cmp (guid, &efi_guid_global) == 0) + if (efi_guid_cmp (guid, &efi_guid_global) != 0) continue; rc = sscanf (name, "Boot%hX%n", &entry, &scanned); if (rc < 0) { From b13f7844623d1207cc777407288b850291b1228d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 21 Jan 2019 16:18:03 -0600 Subject: [PATCH 197/254] trivial: dell: When plugging in a dock supported by dell-dock don't show an error Some aspects of the method for querying dock firmware do work in 'dell' plugin but that is not useful for fwupd because it's incomplete. Due to this the following error shows up in fwupd journal if run on a Dell system when the new Dell dock is plugged in: failed to add USB device 0bda:8153: failed to add device using on dell: invalid dock component request Query 3 0 2 4 0 Detect this scenario, and prevent showing errors in logs. --- plugins/dell/fu-plugin-dell.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 42cff459c..d15228040 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -54,6 +54,7 @@ typedef struct _DOCK_DESCRIPTION #define LEGACY_CBL_STR "2 2 2 1 0" #define UNIV_CBL_STR "2 2 2 2 0" #define TBT_CBL_STR "2 2 2 3 0" +#define FUTURE_EC_STR "3 0 2 4 0" /* supported dock related GUIDs */ #define DOCK_FLASH_GUID "e7ca1f36-bf73-4574-afe6-a4ccacabf479" @@ -202,6 +203,7 @@ fu_plugin_dell_match_dock_component (const gchar *query_str, {TBT_CBL_GUID, TBT_CBL_STR, TBT_CBL_DESC}, {UNIV_CBL_GUID, UNIV_CBL_STR, UNIV_CBL_DESC}, {LEGACY_CBL_GUID, LEGACY_CBL_STR, LEGACY_CBL_DESC}, + {NULL, FUTURE_EC_STR, NULL}, }; for (guint i = 0; i < G_N_ELEMENTS (list); i++) { @@ -395,6 +397,10 @@ fu_plugin_usb_device_added (FuPlugin *plugin, "invalid dock component request %s", query_str); return FALSE; } + if (component_guid == NULL || component_name == NULL) { + g_debug ("%s is supported by another plugin", query_str); + return TRUE; + } /* dock EC hasn't been updated for first time */ if (dock_info->flash_pkg_version == 0x00ffffff) { From 650eea91ee0fcc07fd591f2fd14a0f48c0d51ac0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Jan 2019 10:15:10 +0000 Subject: [PATCH 198/254] trivial: Fix a build issue when building with high -j values --- src/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meson.build b/src/meson.build index 286d4fc14..9b924ec0a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -203,6 +203,7 @@ if get_option('daemon') executable( 'fwupd', resources_src, + fu_hash, sources : [ keyring_src, 'fu-archive.c', From f6a6fe8ec5cc60de2a276732b4d00e48f2b1dd7c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Jan 2019 09:53:17 +0000 Subject: [PATCH 199/254] dfu: Support ihex files with leading comments Also look for the EOF in the file. --- plugins/dfu/dfu-format-ihex.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/dfu/dfu-format-ihex.c b/plugins/dfu/dfu-format-ihex.c index 3d3c9a7ca..8fb68062c 100644 --- a/plugins/dfu/dfu-format-ihex.c +++ b/plugins/dfu/dfu-format-ihex.c @@ -33,9 +33,17 @@ dfu_firmware_detect_ihex (GBytes *bytes) data = (guint8 *) g_bytes_get_data (bytes, &len); if (len < 12) return DFU_FIRMWARE_FORMAT_UNKNOWN; - if (data[0] != ':') - return DFU_FIRMWARE_FORMAT_UNKNOWN; - return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* match the first char */ + if (data[0] == ':') + return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* look for the EOF line */ + if (g_strstr_len ((const gchar *) data, (gssize) len, ":000000") != NULL) + return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* failed */ + return DFU_FIRMWARE_FORMAT_UNKNOWN; } #define DFU_INHX32_RECORD_TYPE_DATA 0x00 From 720b5deb00c1976178db3ac120bc736efde5dd1c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Jan 2019 09:51:19 +0000 Subject: [PATCH 200/254] dfu: Fix the parser to support extended segment addresses Split the data into lines, which is less efficient but also much easier to understand and debug. --- plugins/dfu/dfu-format-ihex.c | 213 ++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 89 deletions(-) diff --git a/plugins/dfu/dfu-format-ihex.c b/plugins/dfu/dfu-format-ihex.c index 8fb68062c..3603fb436 100644 --- a/plugins/dfu/dfu-format-ihex.c +++ b/plugins/dfu/dfu-format-ihex.c @@ -50,10 +50,41 @@ dfu_firmware_detect_ihex (GBytes *bytes) #define DFU_INHX32_RECORD_TYPE_EOF 0x01 #define DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT 0x02 #define DFU_INHX32_RECORD_TYPE_START_SEGMENT 0x03 -#define DFU_INHX32_RECORD_TYPE_EXTENDED 0x04 -#define DFU_INHX32_RECORD_TYPE_ADDR32 0x05 +#define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04 +#define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05 #define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd +static const gchar * +dfu_firmware_ihex_record_type_to_string (guint8 record_type) +{ + if (record_type == DFU_INHX32_RECORD_TYPE_DATA) + return "DATA"; + if (record_type == DFU_INHX32_RECORD_TYPE_EOF) + return "EOF"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT) + return "EXTENDED_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_SEGMENT) + return "START_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR) + return "EXTENDED_LINEAR"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_LINEAR) + return "ADDR32"; + if (record_type == DFU_INHX32_RECORD_TYPE_SIGNATURE) + return "SIGNATURE"; + return NULL; +} + +static gchar ** +_g_strnsplit (const gchar *str, gsize sz, + const gchar *delimiter, gint max_tokens) +{ + if (str[sz - 1] != '\0') { + g_autofree gchar *str2 = g_strndup (str, sz); + return g_strsplit (str2, delimiter, max_tokens); + } + return g_strsplit (str, delimiter, max_tokens); +} + /** * dfu_firmware_from_ihex: (skip) * @firmware: a #DfuFirmware @@ -71,25 +102,19 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, DfuFirmwareParseFlags flags, GError **error) { - const gchar *in_buffer; + const gchar *data; gboolean got_eof = FALSE; - gsize len_in; - guint16 addr_high = 0; - guint16 addr_low = 0; - guint32 addr32 = 0; - guint32 addr32_last = 0; - guint32 element_address = 0; - guint8 checksum; - guint8 data_tmp; - guint8 len_tmp; - guint8 type; - guint end; - guint offset = 0; + gsize sz = 0; + guint32 abs_addr = 0x0; + guint32 addr_last = 0x0; + guint32 base_addr = 0x0; + guint32 seg_addr = 0x0; + g_auto(GStrv) lines = NULL; g_autoptr(DfuElement) element = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(GBytes) contents = NULL; - g_autoptr(GString) string = NULL; - g_autoptr(GString) signature = g_string_new (NULL); + g_autoptr(GString) buf = g_string_new (NULL); + g_autoptr(GString) buf_signature = g_string_new (NULL); g_return_val_if_fail (bytes != NULL, FALSE); @@ -99,95 +124,110 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, element = dfu_element_new (); /* parse records */ - in_buffer = g_bytes_get_data (bytes, &len_in); - string = g_string_new (""); - while (offset < len_in) { + data = g_bytes_get_data (bytes, &sz); + lines = _g_strnsplit ((const gchar *) data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; + guint32 addr; + guint8 byte_cnt; + guint8 record_type; + guint line_end; + + /* ignore comments */ + if (g_str_has_prefix (line, ";")) + continue; + + /* ignore blank lines */ + g_strdelimit (line, "\r", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; /* check starting token */ - if (in_buffer[offset] != ':') { + if (line[0] != ':') { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid starting token, got %c at %x", - in_buffer[offset], offset); + "invalid starting token on line %u: %s", + ln + 1, line); return FALSE; } /* check there's enough data for the smallest possible record */ - if (offset + 12 > (guint) len_in) { + if (linesz < 11) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "record incomplete at %u, length %u", - offset, (guint) len_in); + "line %u is incomplete, length %u", + ln + 1, (guint) linesz); return FALSE; } /* length, 16-bit address, type */ - len_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 1); - addr_low = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 3); - type = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 7); + byte_cnt = dfu_utils_buffer_parse_uint8 (line + 1); + addr = dfu_utils_buffer_parse_uint16 (line + 3); + record_type = dfu_utils_buffer_parse_uint8 (line + 7); + g_debug ("%s:", dfu_firmware_ihex_record_type_to_string (record_type)); + g_debug (" addr_start:\t0x%04x", addr); + g_debug (" length:\t0x%02x", byte_cnt); + addr += seg_addr; + addr += abs_addr; + g_debug (" addr:\t0x%08x", addr); /* position of checksum */ - end = offset + 9 + len_tmp * 2; - if (end > (guint) len_in) { + line_end = 9 + byte_cnt * 2; + if (line_end > (guint) linesz) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "checksum > file length: %u", - end); + "line %u malformed, length: %u", + ln + 1, line_end); return FALSE; } /* verify checksum */ if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { - checksum = 0; - for (guint i = offset + 1; i < end + 2; i += 2) { - data_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + i); + guint8 checksum = 0; + for (guint i = 1; i < line_end + 2; i += 2) { + guint8 data_tmp = dfu_utils_buffer_parse_uint8 (line + i); checksum += data_tmp; } if (checksum != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid record checksum at 0x%04x " - "to 0x%04x, got 0x%02x", - offset, end, checksum); + "line %u has invalid checksum (0x%02x)", + ln + 1, checksum); return FALSE; } } /* process different record types */ - switch (type) { + switch (record_type) { case DFU_INHX32_RECORD_TYPE_DATA: - /* if not contiguous with previous record */ - if ((addr_high + addr_low) != addr32) { - if (addr32 == 0x0) { - g_debug ("base address %08x", addr_low); - dfu_element_set_address (element, addr_low); - } - addr32 = ((guint32) addr_high << 16) + addr_low; - if (element_address == 0x0) - element_address = addr32; - } + /* base address for element */ + if (base_addr == 0x0) + base_addr = addr; /* does not make sense */ - if (addr32 < addr32_last) { + if (addr < addr_last) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid address 0x%x, last was 0x%x", - (guint) addr32, - (guint) addr32_last); + (guint) addr, + (guint) addr_last); return FALSE; } /* parse bytes from line */ - g_debug ("writing data 0x%08x", (guint32) addr32); - for (guint i = offset + 9; i < end; i += 2) { + g_debug ("writing data 0x%08x", (guint32) addr); + for (guint i = 9; i < line_end; i += 2) { /* any holes in the hex record */ - guint32 len_hole = addr32 - addr32_last; - if (addr32_last > 0 && len_hole > 0x100000) { + guint32 len_hole = addr - addr_last; + guint8 data_tmp; + if (addr_last > 0 && len_hole > 0x100000) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -195,19 +235,19 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, (guint) len_hole); return FALSE; } - if (addr32_last > 0x0 && len_hole > 1) { + if (addr_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x", + addr_last + 1, addr_last + len_hole - 1); for (guint j = 1; j < len_hole; j++) { - g_debug ("filling address 0x%08x", - addr32_last + j); /* although 0xff might be clearer, * we can't write 0xffff to pic14 */ - g_string_append_c (string, 0x00); + g_string_append_c (buf, 0x00); } } /* write into buf */ - data_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + i); - g_string_append_c (string, (gchar) data_tmp); - addr32_last = addr32++; + data_tmp = dfu_utils_buffer_parse_uint8 (line + i); + g_string_append_c (buf, (gchar) data_tmp); + addr_last = addr++; } break; case DFU_INHX32_RECORD_TYPE_EOF: @@ -221,25 +261,28 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, } got_eof = TRUE; break; - case DFU_INHX32_RECORD_TYPE_EXTENDED: - addr_high = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 9); - addr32 = ((guint32) addr_high << 16) + addr_low; + case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR: + abs_addr = dfu_utils_buffer_parse_uint16 (line + 9) << 16; + g_debug (" abs_addr:\t0x%02x", abs_addr); break; - case DFU_INHX32_RECORD_TYPE_ADDR32: - addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 9); + case DFU_INHX32_RECORD_TYPE_START_LINEAR: + abs_addr = dfu_utils_buffer_parse_uint32 (line + 9); + g_debug (" abs_addr:\t0x%08x", abs_addr); break; case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT: /* segment base address, so ~1Mb addressable */ - addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 9) * 16; + seg_addr = dfu_utils_buffer_parse_uint16 (line + 9) * 16; + g_debug (" seg_addr:\t0x%08x", seg_addr); break; case DFU_INHX32_RECORD_TYPE_START_SEGMENT: /* initial content of the CS:IP registers */ - addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 9); + seg_addr = dfu_utils_buffer_parse_uint32 (line + 9); + g_debug (" seg_addr:\t0x%02x", seg_addr); break; case DFU_INHX32_RECORD_TYPE_SIGNATURE: - for (guint i = offset + 9; i < end; i += 2) { - guint8 tmp_c = dfu_utils_buffer_parse_uint8 (in_buffer + i); - g_string_append_c (signature, tmp_c); + for (guint i = 9; i < line_end; i += 2) { + guint8 tmp_c = dfu_utils_buffer_parse_uint8 (line + i); + g_string_append_c (buf_signature, tmp_c); } break; default: @@ -250,17 +293,9 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid ihex record type %i", - type); + record_type); return FALSE; } - - /* ignore any line return */ - offset = end + 2; - for (; offset < len_in; offset++) { - if (in_buffer[offset] != '\n' && - in_buffer[offset] != '\r') - break; - } } /* no EOF */ @@ -273,19 +308,19 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, } /* add single image */ - contents = g_bytes_new (string->str, string->len); + contents = g_bytes_new (buf->str, buf->len); dfu_element_set_contents (element, contents); - dfu_element_set_address (element, element_address); + dfu_element_set_address (element, base_addr); dfu_image_add_element (image, element); dfu_firmware_add_image (firmware, image); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); /* add optional signature */ - if (signature->len > 0) { + if (buf_signature->len > 0) { g_autoptr(DfuElement) element_sig = dfu_element_new (); g_autoptr(DfuImage) image_sig = dfu_image_new (); - g_autoptr(GBytes) data = g_bytes_new_static (signature->str, signature->len); - dfu_element_set_contents (element_sig, data); + g_autoptr(GBytes) data_sig = g_bytes_new_static (buf_signature->str, buf_signature->len); + dfu_element_set_contents (element_sig, data_sig); dfu_image_add_element (image_sig, element_sig); dfu_image_set_name (image_sig, "signature"); dfu_firmware_add_image (firmware, image_sig); @@ -337,7 +372,7 @@ dfu_firmware_to_ihex_bytes (GString *str, guint8 record_type, guint8 buf[2]; fu_common_write_uint16 (buf, address_offset, G_BIG_ENDIAN); dfu_firmware_ihex_emit_chunk (str, 0x0, - DFU_INHX32_RECORD_TYPE_EXTENDED, + DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR, buf, 2); address_offset_last = address_offset; } From 42c514764afd643eeaf697231af4af50aa05ccd4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 22 Jan 2019 10:23:21 +0000 Subject: [PATCH 201/254] dfu: Ignore the SUB ASCII value This is probably written by a non-free post-processing tool and can be ignored. --- plugins/dfu/dfu-format-ihex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dfu/dfu-format-ihex.c b/plugins/dfu/dfu-format-ihex.c index 3603fb436..3fcf78dba 100644 --- a/plugins/dfu/dfu-format-ihex.c +++ b/plugins/dfu/dfu-format-ihex.c @@ -139,7 +139,7 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, continue; /* ignore blank lines */ - g_strdelimit (line, "\r", '\0'); + g_strdelimit (lines[ln], "\r\x1a", '\0'); linesz = strlen (line); if (linesz == 0) continue; From 3f243a9e9e431b6175462a0ea08c16e38f840176 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 21 Jan 2019 22:05:23 -0600 Subject: [PATCH 202/254] fu-util/fu-tool: sync up reboot and shutdown behavior It's currently a hodge podge of commands that can install files not always invoking a reboot or shutdown. Move the actual code into `fu-util-common.c` and make sure that all `install` and `update` functions call it now. --- src/fu-tool.c | 88 ++++++++++++++++++++----- src/fu-util-common.c | 121 ++++++++++++++++++++++++++++++++++ src/fu-util-common.h | 7 ++ src/fu-util.c | 154 +++++++------------------------------------ 4 files changed, 222 insertions(+), 148 deletions(-) diff --git a/src/fu-tool.c b/src/fu-tool.c index c40e992db..f4c0ffd69 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -9,6 +9,7 @@ #include "config.h" #include +#include #include #include #include @@ -28,12 +29,16 @@ #define SYSTEMD_MANAGER_INTERFACE "org.freedesktop.systemd1.Manager" #define SYSTEMD_FWUPD_UNIT "fwupd.service" -/* this is only valid in this file */ -#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) - /* custom return code */ #define EXIT_NOTHING_TO_DO 2 +typedef enum { + FU_UTIL_OPERATION_UNKNOWN, + FU_UTIL_OPERATION_UPDATE, + FU_UTIL_OPERATION_INSTALL, + FU_UTIL_OPERATION_LAST +} FuUtilOperation; + typedef struct { GCancellable *cancellable; GMainLoop *loop; @@ -41,10 +46,13 @@ typedef struct { GPtrArray *cmd_array; FuEngine *engine; FuProgressbar *progressbar; + gboolean no_reboot_check; FwupdInstallFlags flags; gboolean show_all_devices; /* only valid in update and downgrade */ + FuUtilOperation current_operation; FwupdDevice *current_device; + FwupdDeviceFlags completion_flags; } FuUtilPrivate; typedef gboolean (*FuUtilPrivateCb) (FuUtilPrivate *util, @@ -537,7 +545,7 @@ fu_util_prompt_for_device (FuUtilPrivate *priv, GError **error) } static void -fu_util_install_device_changed_cb (FwupdClient *client, +fu_util_update_device_changed_cb (FwupdClient *client, FwupdDevice *device, FuUtilPrivate *priv) { @@ -549,11 +557,25 @@ fu_util_install_device_changed_cb (FwupdClient *client, return; /* show message in progressbar */ - /* TRANSLATORS: %1 is a device name */ - str = g_strdup_printf (_("Installing %s"), - fwupd_device_get_name (device)); - fu_progressbar_set_title (priv->progressbar, str); + if (priv->current_operation == FU_UTIL_OPERATION_UPDATE) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Updating %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else if (priv->current_operation == FU_UTIL_OPERATION_INSTALL) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Installing on %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else { + g_warning ("no FuUtilOperation set"); + } g_set_object (&priv->current_device, device); + + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; + else if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; } static gboolean @@ -593,16 +615,21 @@ fu_util_install_blob (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; } + priv->current_operation = FU_UTIL_OPERATION_INSTALL; g_signal_connect (priv->engine, "device-changed", - G_CALLBACK (fu_util_install_device_changed_cb), priv); + G_CALLBACK (fu_util_update_device_changed_cb), priv); /* write bare firmware */ - return fu_engine_install_blob (priv->engine, device, - NULL, /* blob_cab */ - blob_fw, - NULL, /* version */ - priv->flags, - error); + if (!fu_engine_install_blob (priv->engine, device, + NULL, /* blob_cab */ + blob_fw, + NULL, /* version */ + priv->flags, + error)) + return FALSE; + + /* success */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gint @@ -748,15 +775,22 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) return FALSE; } + priv->current_operation = FU_UTIL_OPERATION_INSTALL; g_signal_connect (priv->engine, "device-changed", - G_CALLBACK (fu_util_install_device_changed_cb), priv); + G_CALLBACK (fu_util_update_device_changed_cb), priv); /* install all the tasks */ if (!fu_engine_install_tasks (priv->engine, install_tasks, blob_cab, priv->flags, error)) return FALSE; + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + /* success */ - return TRUE; + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -768,6 +802,10 @@ fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) if (!fu_util_start_engine (priv, error)) return FALSE; + priv->current_operation = FU_UTIL_OPERATION_UPDATE; + g_signal_connect (priv->engine, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + devices = fu_engine_get_devices (priv->engine, error); for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); @@ -822,7 +860,14 @@ fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) } } } - return TRUE; + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -1093,6 +1138,9 @@ main (int argc, char *argv[]) { "force", '\0', 0, G_OPTION_ARG_NONE, &force, /* TRANSLATORS: command line option */ _("Override plugin warning"), NULL }, + { "no-reboot-check", '\0', 0, G_OPTION_ARG_NONE, &priv->no_reboot_check, + /* TRANSLATORS: command line option */ + _("Do not check for reboot after update"), NULL }, { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, /* TRANSLATORS: command line option */ _("Show devices that are not updatable"), NULL }, @@ -1216,6 +1264,10 @@ main (int argc, char *argv[]) g_ptr_array_sort (priv->cmd_array, (GCompareFunc) fu_sort_command_name_cb); + /* non-TTY consoles cannot answer questions */ + if (isatty (fileno (stdout)) == 0) + priv->no_reboot_check = TRUE; + /* get a list of the commands */ priv->context = g_option_context_new (NULL); cmd_descriptions = fu_util_get_descriptions (priv->cmd_array); diff --git a/src/fu-util-common.c b/src/fu-util-common.c index af952e81a..cdeb2ff6b 100644 --- a/src/fu-util-common.c +++ b/src/fu-util-common.c @@ -173,3 +173,124 @@ fu_util_get_versions (void) #endif return g_string_free (string, FALSE); } + +static gboolean +fu_util_update_shutdown (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + +#ifdef HAVE_SYSTEMD + /* shutdown using logind */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "PowerOff", + g_variant_new ("(b)", TRUE), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#elif defined(HAVE_CONSOLEKIT) + /* shutdown using ConsoleKit */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "Stop", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "No supported backend compiled in to perform the operation."); +#endif + return val != NULL; +} + +static gboolean +fu_util_update_reboot (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + +#ifdef HAVE_SYSTEMD + /* reboot using logind */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Reboot", + g_variant_new ("(b)", TRUE), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#elif defined(HAVE_CONSOLEKIT) + /* reboot using ConsoleKit */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "Restart", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "No supported backend compiled in to perform the operation."); +#endif + return val != NULL; +} + +gboolean +fu_util_prompt_complete (FwupdDeviceFlags flags, gboolean prompt, GError **error) +{ + if (flags & FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) { + if (prompt) { + g_print ("\n%s %s [Y|n]: ", + /* TRANSLATORS: explain why we want to shutdown */ + _("An update requires the system to shutdown to complete."), + /* TRANSLATORS: shutdown to apply the update */ + _("Shutdown now?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + } + return fu_util_update_shutdown (error); + } + if (flags & FWUPD_DEVICE_FLAG_NEEDS_REBOOT) { + if (prompt) { + g_print ("\n%s %s [Y|n]: ", + /* TRANSLATORS: explain why we want to reboot */ + _("An update requires a reboot to complete."), + /* TRANSLATORS: reboot to apply the update */ + _("Restart now?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + } + return fu_util_update_reboot (error); + } + + return TRUE; +} diff --git a/src/fu-util-common.h b/src/fu-util-common.h index ac2664c35..d099ec409 100644 --- a/src/fu-util-common.h +++ b/src/fu-util-common.h @@ -10,6 +10,9 @@ #include #include +/* this is only valid for tools */ +#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) + void fu_util_print_data (const gchar *title, const gchar *msg); guint fu_util_prompt_for_number (guint maxnum); @@ -21,4 +24,8 @@ gchar *fu_util_get_user_cache_path (const gchar *fn); gchar *fu_util_get_versions (void); +gboolean fu_util_prompt_complete (FwupdDeviceFlags flags, + gboolean prompt, + GError **error); + #endif /* __FU_UTIL_COMMON_H__ */ diff --git a/src/fu-util.c b/src/fu-util.c index cbe189814..174661fb9 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -29,9 +29,6 @@ #include "fu-util-common.h" #include "fwupd-common-private.h" -/* this is only valid in this file */ -#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) - /* custom return code */ #define EXIT_NOTHING_TO_DO 2 @@ -60,6 +57,7 @@ typedef struct { /* only valid in update and downgrade */ FuUtilOperation current_operation; FwupdDevice *current_device; + FwupdDeviceFlags completion_flags; } FuUtilPrivate; typedef gboolean (*FuUtilPrivateCb) (FuUtilPrivate *util, @@ -230,6 +228,12 @@ fu_util_update_device_changed_cb (FwupdClient *client, g_warning ("no FuUtilOperation set"); } g_set_object (&priv->current_device, device); + + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; + else if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + } static FwupdDevice * @@ -671,7 +675,18 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) filename = fu_util_download_if_required (priv, values[0], error); if (filename == NULL) return FALSE; - return fwupd_client_install (priv->client, id, filename, priv->flags, NULL, error); + + if (!fwupd_client_install (priv->client, id, filename, priv->flags, NULL, error)) + return FALSE; + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + /* show reboot if needed */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -699,96 +714,6 @@ fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } -static gboolean -fu_util_update_reboot (GError **error) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) val = NULL; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) - return FALSE; - -#ifdef HAVE_SYSTEMD - /* reboot using logind */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "Reboot", - g_variant_new ("(b)", TRUE), - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#elif defined(HAVE_CONSOLEKIT) - /* reboot using ConsoleKit */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "Restart", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "No supported backend compiled in to perform the operation."); -#endif - return val != NULL; -} - -static gboolean -fu_util_update_shutdown (GError **error) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) val = NULL; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) - return FALSE; - -#ifdef HAVE_SYSTEMD - /* shutdown using logind */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "PowerOff", - g_variant_new ("(b)", TRUE), - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#elif defined(HAVE_CONSOLEKIT) - /* shutdown using ConsoleKit */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "Stop", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "No supported backend compiled in to perform the operation."); -#endif - return val != NULL; -} - static gboolean fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -891,7 +816,7 @@ fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) } /* reboot */ - if (!fu_util_update_reboot (error)) + if (!fu_util_prompt_complete (FWUPD_DEVICE_FLAG_NEEDS_REBOOT, FALSE, error)) return FALSE; g_print ("%s\n", _("Done!")); @@ -2087,8 +2012,6 @@ fu_util_update_device_with_release (FuUtilPrivate *priv, static gboolean fu_util_update_all (FuUtilPrivate *priv, GError **error) { - gboolean requires_reboot = FALSE; - gboolean requires_shutdown = FALSE; g_autoptr(GPtrArray) devices = NULL; /* get devices from daemon */ @@ -2119,10 +2042,6 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) rel = g_ptr_array_index (rels, 0); if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; - if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) - requires_shutdown = TRUE; - else if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) - requires_reboot = TRUE; } /* we don't want to ask anything */ @@ -2131,27 +2050,7 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) return TRUE; } - /* at least one of the updates needed a reboot */ - if (requires_shutdown) { - g_print ("\n%s %s [Y|n]: ", - /* TRANSLATORS: explain why we want to upload */ - _("An update requires the system to shutdown to complete."), - /* TRANSLATORS: reboot to apply the update */ - _("Shutdown now?")); - if (!fu_util_prompt_for_boolean (TRUE)) - return TRUE; - return fu_util_update_shutdown (error); - } else if (requires_reboot) { - g_print ("\n%s %s [Y|n]: ", - /* TRANSLATORS: explain why we want to upload */ - _("An update requires a reboot to complete."), - /* TRANSLATORS: reboot to apply the update */ - _("Restart now?")); - if (!fu_util_prompt_for_boolean (TRUE)) - return TRUE; - return fu_util_update_reboot (error); - } - return TRUE; + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -2189,14 +2088,9 @@ fu_util_update_by_id (FuUtilPrivate *priv, const gchar *device_id, GError **erro /* the update needs the user to restart the computer */ if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) { - g_print ("\n%s %s [Y|n]: ", - /* TRANSLATORS: exactly one update needs this */ - _("The update requires a reboot to complete."), - /* TRANSLATORS: reboot to apply the update */ - _("Restart now?")); - if (!fu_util_prompt_for_boolean (TRUE)) - return TRUE; - return fu_util_update_reboot (error); + if (!fu_util_prompt_complete (FWUPD_DEVICE_FLAG_NEEDS_REBOOT, TRUE, + error)) + return FALSE; } return TRUE; } From 367f4590d66422f250e28d8c6595c7a1deceeab2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 22 Nov 2018 10:19:05 +0000 Subject: [PATCH 203/254] wacom-raw: Add a plugin to update Wacom embedded EMR and AES panels --- contrib/fwupd.spec.in | 1 + plugins/meson.build | 1 + plugins/wacom-raw/README.md | 26 ++ plugins/wacom-raw/data/hid-recorder.txt | 470 ++++++++++++++++++++++++ plugins/wacom-raw/fu-plugin-wacom-raw.c | 95 +++++ plugins/wacom-raw/fu-wacom-aes-device.c | 246 +++++++++++++ plugins/wacom-raw/fu-wacom-aes-device.h | 21 ++ plugins/wacom-raw/fu-wacom-common.c | 108 ++++++ plugins/wacom-raw/fu-wacom-common.h | 80 ++++ plugins/wacom-raw/fu-wacom-device.c | 420 +++++++++++++++++++++ plugins/wacom-raw/fu-wacom-device.h | 56 +++ plugins/wacom-raw/fu-wacom-emr-device.c | 246 +++++++++++++ plugins/wacom-raw/fu-wacom-emr-device.h | 21 ++ plugins/wacom-raw/meson.build | 31 ++ plugins/wacom-raw/wacom-raw.quirk | 35 ++ 15 files changed, 1857 insertions(+) create mode 100644 plugins/wacom-raw/README.md create mode 100644 plugins/wacom-raw/data/hid-recorder.txt create mode 100644 plugins/wacom-raw/fu-plugin-wacom-raw.c create mode 100644 plugins/wacom-raw/fu-wacom-aes-device.c create mode 100644 plugins/wacom-raw/fu-wacom-aes-device.h create mode 100644 plugins/wacom-raw/fu-wacom-common.c create mode 100644 plugins/wacom-raw/fu-wacom-common.h create mode 100644 plugins/wacom-raw/fu-wacom-device.c create mode 100644 plugins/wacom-raw/fu-wacom-device.h create mode 100644 plugins/wacom-raw/fu-wacom-emr-device.c create mode 100644 plugins/wacom-raw/fu-wacom-emr-device.h create mode 100644 plugins/wacom-raw/meson.build create mode 100644 plugins/wacom-raw/wacom-raw.quirk diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 31f9b64ab..f242438c1 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -293,6 +293,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_unifying.so %{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_raw.so %{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_usb.so %ghost %{_localstatedir}/lib/fwupd/gnupg %if 0%{?have_uefi} diff --git a/plugins/meson.build b/plugins/meson.build index 7d84f63f5..dbd509a35 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -12,6 +12,7 @@ subdir('test') subdir('udev') subdir('unifying') subdir('upower') +subdir('wacom-raw') subdir('wacom-usb') subdir('superio') diff --git a/plugins/wacom-raw/README.md b/plugins/wacom-raw/README.md new file mode 100644 index 000000000..878b99542 --- /dev/null +++ b/plugins/wacom-raw/README.md @@ -0,0 +1,26 @@ +Wacom RAW Support +================= + +Introduction +------------ + +This plugin updates integrated Wacom AES and EMR devices. They are typically +connected using I²C and not USB. + +GUID Generation +--------------- + +The HID DeviceInstanceId values are used, e.g. `HIDRAW\VEN_056A&DEV_4875`. + +Additionally, for supported AES devices an extra GUID is added for the hardware +ID (e.g. `WACOM\HWID_%04X`) to further disambiguate the panels. + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|-------------------------|-------------------------------------|-----------------------| +| `WacomI2cFlashBlockSize`| Block size to transfer firmware | 1.2.4 | +| `WacomI2cFlashBaseAddr` | Base address for firmware | 1.2.4 | +| `WacomI2cFlashSize` | Maximum size of the firmware zone | 1.2.4 | diff --git a/plugins/wacom-raw/data/hid-recorder.txt b/plugins/wacom-raw/data/hid-recorder.txt new file mode 100644 index 000000000..a76b65db5 --- /dev/null +++ b/plugins/wacom-raw/data/hid-recorder.txt @@ -0,0 +1,470 @@ +# WCOM4875:00 056A:4875 +# 0x05, 0x0d, // Usage Page (Digitizers) 0 +# 0x09, 0x04, // Usage (Touch Screen) 2 +# 0xa1, 0x01, // Collection (Application) 4 +# 0x85, 0x0c, // Report ID (12) 6 +# 0x95, 0x01, // Report Count (1) 8 +# 0x75, 0x08, // Report Size (8) 10 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 12 +# 0x15, 0x00, // Logical Minimum (0) 15 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 17 +# 0x09, 0x54, // Usage (Contact Count) 19 +# 0x81, 0x02, // Input (Data,Var,Abs) 21 +# 0x05, 0x0d, // Usage Page (Digitizers) 23 +# 0x09, 0x22, // Usage (Finger) 25 +# 0xa1, 0x02, // Collection (Logical) 27 +# 0x09, 0x42, // Usage (Tip Switch) 29 +# 0x15, 0x00, // Logical Minimum (0) 31 +# 0x25, 0x01, // Logical Maximum (1) 33 +# 0x75, 0x01, // Report Size (1) 35 +# 0x95, 0x01, // Report Count (1) 37 +# 0x81, 0x02, // Input (Data,Var,Abs) 39 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 41 +# 0x09, 0x47, // Usage (Confidence) 43 +# 0x81, 0x02, // Input (Data,Var,Abs) 45 +# 0x95, 0x05, // Report Count (5) 47 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 49 +# 0x75, 0x10, // Report Size (16) 51 +# 0x09, 0x51, // Usage (Contact Id) 53 +# 0x95, 0x01, // Report Count (1) 55 +# 0x81, 0x02, // Input (Data,Var,Abs) 57 +# 0x05, 0x01, // Usage Page (Generic Desktop) 59 +# 0x75, 0x10, // Report Size (16) 61 +# 0x95, 0x01, // Report Count (1) 63 +# 0x55, 0x0e, // Unit Exponent (-2) 65 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 67 +# 0x09, 0x30, // Usage (X) 69 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 71 +# 0x35, 0x00, // Physical Minimum (0) 74 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 76 +# 0x81, 0x02, // Input (Data,Var,Abs) 79 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 81 +# 0x09, 0x31, // Usage (Y) 84 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 86 +# 0x81, 0x02, // Input (Data,Var,Abs) 89 +# 0xc0, // End Collection 91 +# 0x05, 0x0d, // Usage Page (Digitizers) 92 +# 0x09, 0x22, // Usage (Finger) 94 +# 0xa1, 0x02, // Collection (Logical) 96 +# 0x09, 0x42, // Usage (Tip Switch) 98 +# 0x15, 0x00, // Logical Minimum (0) 100 +# 0x25, 0x01, // Logical Maximum (1) 102 +# 0x75, 0x01, // Report Size (1) 104 +# 0x95, 0x01, // Report Count (1) 106 +# 0x81, 0x02, // Input (Data,Var,Abs) 108 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 110 +# 0x09, 0x47, // Usage (Confidence) 112 +# 0x81, 0x02, // Input (Data,Var,Abs) 114 +# 0x95, 0x05, // Report Count (5) 116 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 118 +# 0x75, 0x10, // Report Size (16) 120 +# 0x09, 0x51, // Usage (Contact Id) 122 +# 0x95, 0x01, // Report Count (1) 124 +# 0x81, 0x02, // Input (Data,Var,Abs) 126 +# 0x05, 0x01, // Usage Page (Generic Desktop) 128 +# 0x75, 0x10, // Report Size (16) 130 +# 0x95, 0x01, // Report Count (1) 132 +# 0x55, 0x0e, // Unit Exponent (-2) 134 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 136 +# 0x09, 0x30, // Usage (X) 138 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 140 +# 0x35, 0x00, // Physical Minimum (0) 143 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 145 +# 0x81, 0x02, // Input (Data,Var,Abs) 148 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 150 +# 0x09, 0x31, // Usage (Y) 153 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 155 +# 0x81, 0x02, // Input (Data,Var,Abs) 158 +# 0xc0, // End Collection 160 +# 0x05, 0x0d, // Usage Page (Digitizers) 161 +# 0x09, 0x22, // Usage (Finger) 163 +# 0xa1, 0x02, // Collection (Logical) 165 +# 0x09, 0x42, // Usage (Tip Switch) 167 +# 0x15, 0x00, // Logical Minimum (0) 169 +# 0x25, 0x01, // Logical Maximum (1) 171 +# 0x75, 0x01, // Report Size (1) 173 +# 0x95, 0x01, // Report Count (1) 175 +# 0x81, 0x02, // Input (Data,Var,Abs) 177 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 179 +# 0x09, 0x47, // Usage (Confidence) 181 +# 0x81, 0x02, // Input (Data,Var,Abs) 183 +# 0x95, 0x05, // Report Count (5) 185 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 187 +# 0x75, 0x10, // Report Size (16) 189 +# 0x09, 0x51, // Usage (Contact Id) 191 +# 0x95, 0x01, // Report Count (1) 193 +# 0x81, 0x02, // Input (Data,Var,Abs) 195 +# 0x05, 0x01, // Usage Page (Generic Desktop) 197 +# 0x75, 0x10, // Report Size (16) 199 +# 0x95, 0x01, // Report Count (1) 201 +# 0x55, 0x0e, // Unit Exponent (-2) 203 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 205 +# 0x09, 0x30, // Usage (X) 207 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 209 +# 0x35, 0x00, // Physical Minimum (0) 212 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 214 +# 0x81, 0x02, // Input (Data,Var,Abs) 217 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 219 +# 0x09, 0x31, // Usage (Y) 222 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 224 +# 0x81, 0x02, // Input (Data,Var,Abs) 227 +# 0xc0, // End Collection 229 +# 0x05, 0x0d, // Usage Page (Digitizers) 230 +# 0x09, 0x22, // Usage (Finger) 232 +# 0xa1, 0x02, // Collection (Logical) 234 +# 0x09, 0x42, // Usage (Tip Switch) 236 +# 0x15, 0x00, // Logical Minimum (0) 238 +# 0x25, 0x01, // Logical Maximum (1) 240 +# 0x75, 0x01, // Report Size (1) 242 +# 0x95, 0x01, // Report Count (1) 244 +# 0x81, 0x02, // Input (Data,Var,Abs) 246 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 248 +# 0x09, 0x47, // Usage (Confidence) 250 +# 0x81, 0x02, // Input (Data,Var,Abs) 252 +# 0x95, 0x05, // Report Count (5) 254 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 256 +# 0x75, 0x10, // Report Size (16) 258 +# 0x09, 0x51, // Usage (Contact Id) 260 +# 0x95, 0x01, // Report Count (1) 262 +# 0x81, 0x02, // Input (Data,Var,Abs) 264 +# 0x05, 0x01, // Usage Page (Generic Desktop) 266 +# 0x75, 0x10, // Report Size (16) 268 +# 0x95, 0x01, // Report Count (1) 270 +# 0x55, 0x0e, // Unit Exponent (-2) 272 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 274 +# 0x09, 0x30, // Usage (X) 276 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 278 +# 0x35, 0x00, // Physical Minimum (0) 281 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 283 +# 0x81, 0x02, // Input (Data,Var,Abs) 286 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 288 +# 0x09, 0x31, // Usage (Y) 291 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 293 +# 0x81, 0x02, // Input (Data,Var,Abs) 296 +# 0xc0, // End Collection 298 +# 0x05, 0x0d, // Usage Page (Digitizers) 299 +# 0x09, 0x22, // Usage (Finger) 301 +# 0xa1, 0x02, // Collection (Logical) 303 +# 0x09, 0x42, // Usage (Tip Switch) 305 +# 0x15, 0x00, // Logical Minimum (0) 307 +# 0x25, 0x01, // Logical Maximum (1) 309 +# 0x75, 0x01, // Report Size (1) 311 +# 0x95, 0x01, // Report Count (1) 313 +# 0x81, 0x02, // Input (Data,Var,Abs) 315 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 317 +# 0x09, 0x47, // Usage (Confidence) 319 +# 0x81, 0x02, // Input (Data,Var,Abs) 321 +# 0x95, 0x05, // Report Count (5) 323 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 325 +# 0x75, 0x10, // Report Size (16) 327 +# 0x09, 0x51, // Usage (Contact Id) 329 +# 0x95, 0x01, // Report Count (1) 331 +# 0x81, 0x02, // Input (Data,Var,Abs) 333 +# 0x05, 0x01, // Usage Page (Generic Desktop) 335 +# 0x75, 0x10, // Report Size (16) 337 +# 0x95, 0x01, // Report Count (1) 339 +# 0x55, 0x0e, // Unit Exponent (-2) 341 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 343 +# 0x09, 0x30, // Usage (X) 345 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 347 +# 0x35, 0x00, // Physical Minimum (0) 350 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 352 +# 0x81, 0x02, // Input (Data,Var,Abs) 355 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 357 +# 0x09, 0x31, // Usage (Y) 360 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 362 +# 0x81, 0x02, // Input (Data,Var,Abs) 365 +# 0xc0, // End Collection 367 +# 0x05, 0x0d, // Usage Page (Digitizers) 368 +# 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 370 +# 0x75, 0x10, // Report Size (16) 375 +# 0x95, 0x01, // Report Count (1) 377 +# 0x09, 0x56, // Usage (Scan Time) 379 +# 0x81, 0x02, // Input (Data,Var,Abs) 381 +# 0x85, 0x0c, // Report ID (12) 383 +# 0x09, 0x55, // Usage (Contact Max) 385 +# 0x75, 0x08, // Report Size (8) 387 +# 0x95, 0x01, // Report Count (1) 389 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 391 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 394 +# 0x85, 0x0a, // Report ID (10) 396 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 398 +# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 401 +# 0x96, 0x00, 0x01, // Report Count (256) 403 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 406 +# 0xc0, // End Collection 408 +# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 409 +# 0x09, 0x11, // Usage (Vendor Usage 0x11) 412 +# 0xa1, 0x01, // Collection (Application) 414 +# 0x85, 0x03, // Report ID (3) 416 +# 0xa1, 0x02, // Collection (Logical) 418 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 420 +# 0x75, 0x08, // Report Size (8) 422 +# 0x15, 0x00, // Logical Minimum (0) 424 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 426 +# 0x95, 0x27, // Report Count (39) 429 +# 0x81, 0x02, // Input (Data,Var,Abs) 431 +# 0xc0, // End Collection 433 +# 0x85, 0x02, // Report ID (2) 434 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 436 +# 0x95, 0x01, // Report Count (1) 438 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 440 +# 0x85, 0x03, // Report ID (3) 442 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 444 +# 0x95, 0x3f, // Report Count (63) 446 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 448 +# 0x85, 0x04, // Report ID (4) 450 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 452 +# 0x95, 0x0f, // Report Count (15) 454 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 456 +# 0x85, 0x07, // Report ID (7) 458 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 460 +# 0x96, 0x00, 0x01, // Report Count (256) 462 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 465 +# 0x85, 0x08, // Report ID (8) 467 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 469 +# 0x96, 0x87, 0x00, // Report Count (135) 471 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 474 +# 0x85, 0x09, // Report ID (9) 476 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 478 +# 0x96, 0x3f, 0x00, // Report Count (63) 480 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 483 +# 0x85, 0x0d, // Report ID (13) 485 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 487 +# 0x95, 0x07, // Report Count (7) 489 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 491 +# 0xc0, // End Collection 493 +# 0x05, 0x0d, // Usage Page (Digitizers) 494 +# 0x09, 0x0e, // Usage (Device Configuration) 496 +# 0xa1, 0x01, // Collection (Application) 498 +# 0x85, 0x0e, // Report ID (14) 500 +# 0x09, 0x23, // Usage (Device Settings) 502 +# 0xa1, 0x02, // Collection (Logical) 504 +# 0x09, 0x52, // Usage (Inputmode) 506 +# 0x09, 0x53, // Usage (Device Index) 508 +# 0x15, 0x00, // Logical Minimum (0) 510 +# 0x25, 0x0a, // Logical Maximum (10) 512 +# 0x75, 0x08, // Report Size (8) 514 +# 0x95, 0x02, // Report Count (2) 516 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 518 +# 0xc0, // End Collection 520 +# 0xc0, // End Collection 521 +# 0x05, 0x0d, // Usage Page (Digitizers) 522 +# 0x09, 0x02, // Usage (Pen) 524 +# 0xa1, 0x01, // Collection (Application) 526 +# 0x85, 0x06, // Report ID (6) 528 +# 0xa4, // Push 530 +# 0x09, 0x20, // Usage (Stylus) 531 +# 0xa1, 0x00, // Collection (Physical) 533 +# 0x09, 0x42, // Usage (Tip Switch) 535 +# 0x09, 0x44, // Usage (Barrel Switch) 537 +# 0x09, 0x45, // Usage (Eraser) 539 +# 0x09, 0x3c, // Usage (Invert) 541 +# 0x09, 0x5a, // Usage (Secondary Barrel Switch) 543 +# 0x09, 0x32, // Usage (In Range) 545 +# 0x15, 0x00, // Logical Minimum (0) 547 +# 0x25, 0x01, // Logical Maximum (1) 549 +# 0x75, 0x01, // Report Size (1) 551 +# 0x95, 0x06, // Report Count (6) 553 +# 0x81, 0x02, // Input (Data,Var,Abs) 555 +# 0x95, 0x02, // Report Count (2) 557 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 559 +# 0x05, 0x01, // Usage Page (Generic Desktop) 561 +# 0x09, 0x30, // Usage (X) 563 +# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 565 +# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 570 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 575 +# 0x55, 0x0d, // Unit Exponent (-3) 577 +# 0x75, 0x10, // Report Size (16) 579 +# 0x95, 0x01, // Report Count (1) 581 +# 0x81, 0x02, // Input (Data,Var,Abs) 583 +# 0x09, 0x31, // Usage (Y) 585 +# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 587 +# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 592 +# 0x81, 0x02, // Input (Data,Var,Abs) 597 +# 0x45, 0x00, // Physical Maximum (0) 599 +# 0x65, 0x00, // Unit (None) 601 +# 0x55, 0x00, // Unit Exponent (0) 603 +# 0x05, 0x0d, // Usage Page (Digitizers) 605 +# 0x09, 0x30, // Usage (Tip Pressure) 607 +# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 609 +# 0x75, 0x10, // Report Size (16) 612 +# 0x81, 0x02, // Input (Data,Var,Abs) 614 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 616 +# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 619 +# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 621 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 624 +# 0x75, 0x10, // Report Size (16) 627 +# 0x81, 0x02, // Input (Data,Var,Abs) 629 +# 0x05, 0x0d, // Usage Page (Digitizers) 631 +# 0x09, 0x5b, // Usage (Transducer Serial Number) 633 +# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 635 +# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 640 +# 0x75, 0x20, // Report Size (32) 645 +# 0x81, 0x02, // Input (Data,Var,Abs) 647 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 649 +# 0x09, 0x00, // Usage (Undefined) 652 +# 0x75, 0x08, // Report Size (8) 654 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 656 +# 0x15, 0x00, // Logical Minimum (0) 659 +# 0x81, 0x02, // Input (Data,Var,Abs) 661 +# 0x05, 0x0d, // Usage Page (Digitizers) 663 +# 0x09, 0x3b, // Usage (Battery Strength) 665 +# 0x81, 0x02, // Input (Data,Var,Abs) 667 +# 0x65, 0x14, // Unit (Degrees,EngRotation) 669 +# 0x55, 0x00, // Unit Exponent (0) 671 +# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 673 +# 0x26, 0x5a, 0x00, // Logical Maximum (90) 676 +# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 679 +# 0x46, 0x5a, 0x00, // Physical Maximum (90) 682 +# 0x75, 0x08, // Report Size (8) 685 +# 0x09, 0x3d, // Usage (X Tilt) 687 +# 0x81, 0x02, // Input (Data,Var,Abs) 689 +# 0x09, 0x3e, // Usage (Y Tilt) 691 +# 0x81, 0x02, // Input (Data,Var,Abs) 693 +# 0xc0, // End Collection 695 +# 0xb4, // Pop 696 +# 0x85, 0x13, // Report ID (19) 697 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 699 +# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 702 +# 0x96, 0x00, 0x01, // Report Count (256) 704 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 707 +# 0xc0, // End Collection 709 +# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 710 +# 0x09, 0x02, // Usage (Vendor Usage 0x02) 713 +# 0xa1, 0x01, // Collection (Application) 715 +# 0x85, 0x0b, // Report ID (11) 717 +# 0xa4, // Push 719 +# 0x09, 0x20, // Usage (Vendor Usage 0x20) 720 +# 0xa1, 0x00, // Collection (Physical) 722 +# 0x09, 0x42, // Usage (Vendor Usage 0x42) 724 +# 0x09, 0x44, // Usage (Vendor Usage 0x44) 726 +# 0x09, 0x45, // Usage (Vendor Usage 0x45) 728 +# 0x09, 0x3c, // Usage (Vendor Usage 0x3c) 730 +# 0x09, 0x5a, // Usage (Vendor Usage 0x5a) 732 +# 0x09, 0x32, // Usage (Vendor Usage 0x32) 734 +# 0x15, 0x00, // Logical Minimum (0) 736 +# 0x25, 0x01, // Logical Maximum (1) 738 +# 0x75, 0x01, // Report Size (1) 740 +# 0x95, 0x06, // Report Count (6) 742 +# 0x81, 0x02, // Input (Data,Var,Abs) 744 +# 0x95, 0x02, // Report Count (2) 746 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 748 +# 0x05, 0x01, // Usage Page (Generic Desktop) 750 +# 0x09, 0x30, // Usage (X) 752 +# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 754 +# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 759 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 764 +# 0x55, 0x0d, // Unit Exponent (-3) 766 +# 0x75, 0x10, // Report Size (16) 768 +# 0x95, 0x01, // Report Count (1) 770 +# 0x81, 0x02, // Input (Data,Var,Abs) 772 +# 0x09, 0x31, // Usage (Y) 774 +# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 776 +# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 781 +# 0x81, 0x02, // Input (Data,Var,Abs) 786 +# 0x45, 0x00, // Physical Maximum (0) 788 +# 0x65, 0x00, // Unit (None) 790 +# 0x55, 0x00, // Unit Exponent (0) 792 +# 0x05, 0x0d, // Usage Page (Digitizers) 794 +# 0x09, 0x30, // Usage (Tip Pressure) 796 +# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 798 +# 0x75, 0x10, // Report Size (16) 801 +# 0x81, 0x02, // Input (Data,Var,Abs) 803 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 805 +# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 808 +# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 810 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 813 +# 0x75, 0x10, // Report Size (16) 816 +# 0x81, 0x02, // Input (Data,Var,Abs) 818 +# 0x05, 0x0d, // Usage Page (Digitizers) 820 +# 0x09, 0x5b, // Usage (Transducer Serial Number) 822 +# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 824 +# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 829 +# 0x75, 0x20, // Report Size (32) 834 +# 0x81, 0x02, // Input (Data,Var,Abs) 836 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 838 +# 0x09, 0x00, // Usage (Undefined) 841 +# 0x75, 0x08, // Report Size (8) 843 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 845 +# 0x15, 0x00, // Logical Minimum (0) 848 +# 0x81, 0x02, // Input (Data,Var,Abs) 850 +# 0x05, 0x0d, // Usage Page (Digitizers) 852 +# 0x09, 0x3b, // Usage (Battery Strength) 854 +# 0x81, 0x02, // Input (Data,Var,Abs) 856 +# 0x65, 0x14, // Unit (Degrees,EngRotation) 858 +# 0x55, 0x00, // Unit Exponent (0) 860 +# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 862 +# 0x26, 0x5a, 0x00, // Logical Maximum (90) 865 +# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 868 +# 0x46, 0x5a, 0x00, // Physical Maximum (90) 871 +# 0x75, 0x08, // Report Size (8) 874 +# 0x09, 0x3d, // Usage (X Tilt) 876 +# 0x81, 0x02, // Input (Data,Var,Abs) 878 +# 0x09, 0x3e, // Usage (Y Tilt) 880 +# 0x81, 0x02, // Input (Data,Var,Abs) 882 +# 0xc0, // End Collection 884 +# 0xb4, // Pop 885 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 886 +# 0x75, 0x08, // Report Size (8) 889 +# 0x15, 0x00, // Logical Minimum (0) 891 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 893 +# 0x85, 0x05, // Report ID (5) 896 +# 0x09, 0x00, // Usage (Undefined) 898 +# 0x95, 0x3a, // Report Count (58) 900 +# 0x81, 0x02, // Input (Data,Var,Abs) 902 +# 0x85, 0x10, // Report ID (16) 904 +# 0x09, 0x00, // Usage (Undefined) 906 +# 0x95, 0x14, // Report Count (20) 908 +# 0x81, 0x02, // Input (Data,Var,Abs) 910 +# 0x85, 0x0f, // Report ID (15) 912 +# 0x09, 0x00, // Usage (Undefined) 914 +# 0x95, 0x28, // Report Count (40) 916 +# 0x81, 0x02, // Input (Data,Var,Abs) 918 +# 0x85, 0x0f, // Report ID (15) 920 +# 0x09, 0x00, // Usage (Undefined) 922 +# 0x95, 0x07, // Report Count (7) 924 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 926 +# 0x85, 0x11, // Report ID (17) 928 +# 0x09, 0x00, // Usage (Undefined) 930 +# 0x95, 0x09, // Report Count (9) 932 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 934 +# 0x85, 0x05, // Report ID (5) 936 +# 0x09, 0x00, // Usage (Undefined) 938 +# 0x95, 0x08, // Report Count (8) 940 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 942 +# 0x85, 0x10, // Report ID (16) 944 +# 0x09, 0x00, // Usage (Undefined) 946 +# 0x96, 0x3f, 0x00, // Report Count (63) 948 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 951 +# 0x85, 0x0b, // Report ID (11) 953 +# 0x09, 0x00, // Usage (Undefined) 955 +# 0x96, 0x3f, 0x00, // Report Count (63) 957 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 960 +# 0xc0, // End Collection 962 +# 0x05, 0x01, // Usage Page (Generic Desktop) 963 +# 0x09, 0x02, // Usage (Mouse) 965 +# 0xa1, 0x01, // Collection (Application) 967 +# 0x85, 0x01, // Report ID (1) 969 +# 0x09, 0x01, // Usage (Pointer) 971 +# 0xa1, 0x00, // Collection (Physical) 973 +# 0x05, 0x09, // Usage Page (Button) 975 +# 0x19, 0x01, // Usage Minimum (1) 977 +# 0x29, 0x02, // Usage Maximum (2) 979 +# 0x15, 0x00, // Logical Minimum (0) 981 +# 0x25, 0x01, // Logical Maximum (1) 983 +# 0x95, 0x02, // Report Count (2) 985 +# 0x75, 0x01, // Report Size (1) 987 +# 0x81, 0x02, // Input (Data,Var,Abs) 989 +# 0x95, 0x01, // Report Count (1) 991 +# 0x75, 0x06, // Report Size (6) 993 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 995 +# 0x05, 0x01, // Usage Page (Generic Desktop) 997 +# 0x09, 0x30, // Usage (X) 999 +# 0x09, 0x31, // Usage (Y) 1001 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 1003 +# 0x75, 0x10, // Report Size (16) 1006 +# 0x95, 0x02, // Report Count (2) 1008 +# 0x81, 0x02, // Input (Data,Var,Abs) 1010 +# 0xc0, // End Collection 1012 +# 0xc0, // End Collection 1013 diff --git a/plugins/wacom-raw/fu-plugin-wacom-raw.c b/plugins/wacom-raw/fu-plugin-wacom-raw.c new file mode 100644 index 000000000..75c928462 --- /dev/null +++ b/plugins/wacom-raw/fu-plugin-wacom-raw.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-wacom-aes-device.h" +#include "fu-wacom-emr-device.h" +#include "fu-wacom-common.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "hidraw"); +} + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "hidraw") != 0) + return TRUE; + + /* wacom */ + if (fu_udev_device_get_vendor (device) != FU_WACOM_DEVICE_VID) + return TRUE; + + /* no actual device to open */ + if (g_udev_device_get_device_file (fu_udev_device_get_dev (device)) == NULL) + return TRUE; + + /* EMR */ + if (fu_device_has_guid (FU_DEVICE (device), "WacomEMR")) { + g_autoptr(FuWacomEmrDevice) dev = fu_wacom_emr_device_new (device); + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* AES */ + if (fu_device_has_guid (FU_DEVICE (device), "WacomAES")) { + g_autoptr(FuWacomAesDevice) dev = fu_wacom_aes_device_new (device); + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* not supported */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Only EMR or AES devices are supported"); + return FALSE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, error); +} diff --git a/plugins/wacom-raw/fu-wacom-aes-device.c b/plugins/wacom-raw/fu-wacom-aes-device.c new file mode 100644 index 000000000..5cfb55e5c --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-aes-device.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-aes-device.h" + +struct _FuWacomAesDevice { + FuWacomDevice parent_instance; + guint32 hwid; +}; + +G_DEFINE_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU_TYPE_WACOM_DEVICE) + +static gboolean +fu_wacom_aes_device_obtain_hwid (FuWacomAesDevice *self, GError **error) +{ + guint8 cmd[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 }; + guint8 buf[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 }; + + cmd[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID; + cmd[1] = 0x01; /* ?? */ + cmd[2] = 0x01; /* ?? */ + cmd[3] = 0x0f; /* ?? */ + + if (!fu_wacom_device_set_feature (FU_WACOM_DEVICE (self), + cmd, sizeof(cmd), error)) { + g_prefix_error (error, "failed to send: "); + return FALSE; + } + buf[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID; + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + if (buf[1] == 0xff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "firmware does not support this feature"); + return FALSE; + } + + /* check magic number */ + if (memcmp (buf, "\x34\x12\x78\x56\x65\x87\x21\x43", 8) != 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "incorrect magic number"); + return FALSE; + } + + /* format the value */ + self->hwid = ((guint32) buf[9]) << 24 | + ((guint32) buf[8]) << 16 | + ((guint32) buf[11]) << 8 | + ((guint32) buf[10]); + return TRUE; + +} + +static gboolean +fu_wacom_aes_query_operation_mode (FuWacomAesDevice *self, GError **error) +{ + guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = { + FU_WACOM_RAW_FW_REPORT_ID, + FU_WACOM_RAW_FW_CMD_QUERY_MODE, + }; + + /* 0x00=runtime, 0x02=bootloader */ + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), buf, sizeof(buf), error)) + return FALSE; + if (buf[1] == 0x00) { + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; + } + if (buf[1] == 0x02) { + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; + } + + /* unsupported */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Failed to query operation mode, got 0x%x", + buf[1]); + return FALSE; +} + +static gboolean +fu_wacom_aes_device_setup (FuDevice *device, GError **error) +{ + FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device); + + /* find out if in bootloader mode already */ + if (!fu_wacom_aes_query_operation_mode (self, error)) + return FALSE; + + /* get firmware version */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_set_version (device, "0.0"); + } else { + guint32 fw_ver; + guint8 data[FU_WACOM_RAW_STATUS_REPORT_SZ] = { + FU_WACOM_RAW_STATUS_REPORT_ID, + 0x0 + }; + g_autofree gchar *version = NULL; + g_autoptr(GError) error_local = NULL; + + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + data, sizeof(data), error)) + return FALSE; + fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + version = g_strdup_printf ("%04x.%02x", fw_ver, data[13]); + fu_device_set_version (device, version); + + /* get the optional 32 byte HWID and add it as a GUID */ + if (!fu_wacom_aes_device_obtain_hwid (self, &error_local)) { + g_debug ("failed to get HwID: %s", error_local->message); + } else { + g_autofree gchar *guid = NULL; + guid = g_strdup_printf ("WACOM\\HWID_%04X", self->hwid); + fu_device_add_guid (device, guid); + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wacom_aes_device_erase_all (FuWacomAesDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, + 2000 * 1000, /* this takes a long time */ + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to send eraseall command: "); + return FALSE; + } + g_usleep (2 * G_USEC_PER_SEC); + return TRUE; +} + +static gboolean +fu_wacom_aes_device_write_block (FuWacomAesDevice *self, + guint32 idx, + guint32 address, + const guint8 *data, + guint16 datasz, + GError **error) +{ + guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self)); + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH, + .echo = (guint8) idx + 1, + .addr = GUINT32_TO_LE(address), + .size8 = datasz / 8, + .data = { 0x00 }, + }; + FuWacomRawResponse rsp = { 0x00 }; + + /* check size */ + if (datasz != blocksz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "block size 0x%x != 0x%x untested", + datasz, (guint) blocksz); + return FALSE; + } + memcpy (&req.data, data, datasz); + + /* write */ + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 1000, + FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) { + g_prefix_error (error, "failed to write block %u: ", idx); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_aes_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error) +{ + FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device); + + /* erase */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wacom_aes_device_erase_all (self, error)) + return FALSE; + + /* write */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_wacom_aes_device_write_block (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + return TRUE; +} + +static void +fu_wacom_aes_device_init (FuWacomAesDevice *self) +{ + fu_device_set_name (FU_DEVICE (self), "Embedded Wacom AES Device"); +} + +static void +fu_wacom_aes_device_class_init (FuWacomAesDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass); + klass_device->setup = fu_wacom_aes_device_setup; + klass_wac_device->write_firmware = fu_wacom_aes_device_write_firmware; +} + +FuWacomAesDevice * +fu_wacom_aes_device_new (FuUdevDevice *device) +{ + FuWacomAesDevice *self = g_object_new (FU_TYPE_WACOM_AES_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff --git a/plugins/wacom-raw/fu-wacom-aes-device.h b/plugins/wacom-raw/fu-wacom-aes-device.h new file mode 100644 index 000000000..07c61c5b8 --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-aes-device.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_WACOM_AES_DEVICE_H +#define __FU_WACOM_AES_DEVICE_H + +#include "fu-wacom-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_AES_DEVICE (fu_wacom_aes_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU, WACOM_AES_DEVICE, FuWacomDevice) + +FuWacomAesDevice *fu_wacom_aes_device_new (FuUdevDevice *device); + +G_END_DECLS + +#endif /* __FU_WACOM_AES_DEVICE_H */ diff --git a/plugins/wacom-raw/fu-wacom-common.c b/plugins/wacom-raw/fu-wacom-common.c new file mode 100644 index 000000000..07fd250a3 --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-common.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wacom-common.h" + +gboolean +fu_wacom_common_check_reply (const FuWacomRawRequest *req, + const FuWacomRawResponse *rsp, + GError **error) +{ + if (rsp->report_id != FU_WACOM_RAW_BL_REPORT_ID_GET) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "report ID failed, expected 0x%02x, got 0x%02x", + (guint) FU_WACOM_RAW_BL_REPORT_ID_GET, + req->report_id); + return FALSE; + } + if (req->cmd != rsp->cmd) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cmd failed, expected 0x%02x, got 0x%02x", + req->cmd, rsp->cmd); + return FALSE; + } + if (req->echo != rsp->echo) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "echo failed, expected 0x%02x, got 0x%02x", + req->echo, rsp->echo); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp, GError **error) +{ + if (rsp->resp == FU_WACOM_RAW_RC_OK) + return TRUE; + if (rsp->resp == FU_WACOM_RAW_RC_BUSY) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_BUSY, + "device is busy"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_MCUTYPE) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "MCU type does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_PID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "PID does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum1 does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM2) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum2 does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_TIMEOUT) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "command timed out"); + return FALSE; + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unknown error 0x%02x", rsp->resp); + return FALSE; +} + +gboolean +fu_wacom_common_block_is_empty (const guint8 *data, guint16 datasz) +{ + for (guint16 i = 0; i < datasz; i++) { + if (data[i] != 0xff) + return FALSE; + } + return TRUE; +} diff --git a/plugins/wacom-raw/fu-wacom-common.h b/plugins/wacom-raw/fu-wacom-common.h new file mode 100644 index 000000000..c142c0e48 --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-common.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_WACOM_COMMON_H +#define __FU_WACOM_COMMON_H + +#include + +G_BEGIN_DECLS + +#define FU_WACOM_DEVICE_VID 0x056A +#define FU_WACOM_RAW_CMD_RETRIES 1000 + +#define FU_WACOM_RAW_STATUS_REPORT_ID 0x04 +#define FU_WACOM_RAW_STATUS_REPORT_SZ 16 + +#define FU_WACOM_RAW_FW_REPORT_ID 0x02 +#define FU_WACOM_RAW_FW_CMD_QUERY_MODE 0x00 +#define FU_WACOM_RAW_FW_CMD_DETACH 0x02 +#define FU_WACOM_RAW_FW_REPORT_SZ 2 + +#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID 0x09 +#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ 64 + +#define FU_WACOM_RAW_BL_REPORT_ID_SET 0x07 +#define FU_WACOM_RAW_BL_REPORT_ID_GET 0x08 + +#define FU_WACOM_RAW_BL_CMD_ERASE_FLASH 0x00 +#define FU_WACOM_RAW_BL_CMD_WRITE_FLASH 0x01 +#define FU_WACOM_RAW_BL_CMD_VERIFY_FLASH 0x02 +#define FU_WACOM_RAW_BL_CMD_ATTACH 0x03 +#define FU_WACOM_RAW_BL_CMD_GET_BLVER 0x04 +#define FU_WACOM_RAW_BL_CMD_GET_MPUTYPE 0x05 +#define FU_WACOM_RAW_BL_CMD_CHECK_MODE 0x07 +#define FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM 0x0e +#define FU_WACOM_RAW_BL_CMD_ALL_ERASE 0x90 + +#define FU_WACOM_RAW_RC_OK 0x00 +#define FU_WACOM_RAW_RC_BUSY 0x80 +#define FU_WACOM_RAW_RC_MCUTYPE 0x0c +#define FU_WACOM_RAW_RC_PID 0x0d +#define FU_WACOM_RAW_RC_CHECKSUM1 0x81 +#define FU_WACOM_RAW_RC_CHECKSUM2 0x82 +#define FU_WACOM_RAW_RC_TIMEOUT 0x87 +#define FU_WACOM_RAW_RC_IN_PROGRESS 0xff + +#define FU_WACOM_RAW_ECHO_DEFAULT g_random_int_range(0xa0,0xfe) + +typedef struct __attribute__((packed)) { + guint8 report_id; + guint8 cmd; + guint8 echo; + guint32 addr; + guint8 size8; + guint8 data[128]; + guint8 data_unused[121]; +} FuWacomRawRequest; + +typedef struct __attribute__((packed)) { + guint8 report_id; + guint8 cmd; + guint8 echo; + guint8 resp; + guint8 data_unused[132]; +} FuWacomRawResponse; + +gboolean fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp, + GError **error); +gboolean fu_wacom_common_check_reply (const FuWacomRawRequest *req, + const FuWacomRawResponse *rsp, + GError **error); +gboolean fu_wacom_common_block_is_empty (const guint8 *data, + guint16 datasz); + +G_END_DECLS + +#endif /* __FU_WACOM_COMMON_H */ diff --git a/plugins/wacom-raw/fu-wacom-device.c b/plugins/wacom-raw/fu-wacom-device.c new file mode 100644 index 000000000..ddeb85879 --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-device.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-device.h" +#include "dfu-firmware.h" + +typedef struct +{ + gint fd; + guint flash_block_size; + guint32 flash_base_addr; + guint32 flash_size; +} FuWacomDevicePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuWacomDevice, fu_wacom_device, FU_TYPE_UDEV_DEVICE) + +#define GET_PRIVATE(o) (fu_wacom_device_get_instance_private (o)) + +static void +fu_wacom_device_to_string (FuDevice *device, GString *str) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + g_string_append (str, " FuWacomDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", priv->fd); + g_string_append_printf (str, " flash-block-size:\t0x%04x\n", priv->flash_block_size); + g_string_append_printf (str, " flash-base-addr:\t0x%04x\n", priv->flash_base_addr); + g_string_append_printf (str, " flash-size:\t\t0x%04x\n", priv->flash_size); +} + +guint +fu_wacom_device_get_block_sz (FuWacomDevice *self) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + return priv->flash_block_size; +} + +guint +fu_wacom_device_get_base_addr (FuWacomDevice *self) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + return priv->flash_base_addr; +} + +gboolean +fu_wacom_device_check_mpu (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_GET_MPUTYPE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to get MPU type: "); + return FALSE; + } + + /* W9013 */ + if (rsp.resp == 0x2e) { + fu_device_add_guid (FU_DEVICE (self), "WacomEMR_W9013"); + return TRUE; + } + + /* W9021 */ + if (rsp.resp == 0x45) { + fu_device_add_guid (FU_DEVICE (self), "WacomEMR_W9021"); + return TRUE; + } + + /* unsupported */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "MPU is not W9013 or W9021: 0x%x", + rsp.resp); + return FALSE; +} + +static gboolean +fu_wacom_device_open (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* open device */ + priv->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDWR); + if (priv->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s", + g_udev_device_get_device_file (udev_device)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wacom_device_close (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (!g_close (priv->fd, error)) + return FALSE; + priv->fd = 0; + return TRUE; +} + +static gboolean +fu_wacom_device_probe (FuUdevDevice *device, GError **error) +{ + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "hid", error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_wacom_device_detach (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = { + FU_WACOM_RAW_FW_REPORT_ID, + FU_WACOM_RAW_FW_CMD_DETACH, + }; + if (!fu_wacom_device_set_feature (self, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to switch to bootloader mode: "); + return FALSE; + } + g_usleep (300 * 1000); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_wacom_device_attach (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomRawRequest req = { + .report_id = FU_WACOM_RAW_BL_REPORT_ID_SET, + .cmd = FU_WACOM_RAW_BL_CMD_ATTACH, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + if (!fu_wacom_device_set_feature (self, (const guint8 *) &req, sizeof(req), error)) { + g_prefix_error (error, "failed to switch to runtime mode: "); + return FALSE; + } + /* only required on AES, but harmless for EMR */ + g_usleep (300 * 1000); + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_wacom_device_check_mode (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_CHECK_MODE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (self, &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to check mode: "); + return FALSE; + } + if (rsp.resp != 0x06) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "check mode failed, mode=0x%02x", + rsp.resp); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_device_set_version_bootloader (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_GET_BLVER, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + g_autofree gchar *version = NULL; + if (!fu_wacom_device_cmd (self, &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to get bootloader version: "); + return FALSE; + } + version = g_strdup_printf ("%u", rsp.resp); + fu_device_set_version_bootloader (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_wacom_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + FuWacomDeviceClass *klass = FU_WACOM_DEVICE_GET_CLASS (device); + DfuElement *element; + DfuImage *image; + GBytes *fw_new; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(GPtrArray) chunks = NULL; + + /* parse hex file */ + if (!dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) + return FALSE; + if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "expected firmware format is 'ihex', got '%s'", + dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); + return FALSE; + } + + /* use the correct image from the firmware */ + image = dfu_firmware_get_image_default (firmware); + if (image == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware image"); + return FALSE; + } + element = dfu_image_get_element_default (image); + if (element == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no element in image"); + return FALSE; + } + g_debug ("using element at addr 0x%0x", + (guint) dfu_element_get_address (element)); + + /* check start address and size */ + if (dfu_element_get_address (element) != priv->flash_base_addr) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "base addr invalid: 0x%05x", + (guint) dfu_element_get_address (element)); + return FALSE; + } + fw_new = dfu_element_get_contents (element); + if (g_bytes_get_size (fw_new) > priv->flash_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "size is invalid: 0x%05x", + (guint) g_bytes_get_size (fw_new)); + return FALSE; + } + + /* we're in bootloader mode now */ + if (!fu_wacom_device_check_mode (self, error)) + return FALSE; + if (!fu_wacom_device_set_version_bootloader (self, error)) + return FALSE; + + /* flash chunks */ + chunks = fu_chunk_array_new_from_bytes (fw_new, priv->flash_base_addr, + 0x00, /* page_sz */ + priv->flash_block_size); + return klass->write_firmware (device, chunks, error); +} + +gboolean +fu_wacom_device_set_feature (FuWacomDevice *self, + const guint8 *data, + guint datasz, + GError **error) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + + /* Set Feature */ + fu_common_dump_raw (G_LOG_DOMAIN, "SetFeature", data, datasz); + if (ioctl (priv->fd, HIDIOCSFEATURE(datasz), data) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to SetFeature"); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wacom_device_get_feature (FuWacomDevice *self, + guint8 *data, + guint datasz, + GError **error) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (ioctl (priv->fd, HIDIOCGFEATURE(datasz), data) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to GetFeature"); + return FALSE; + } + fu_common_dump_raw (G_LOG_DOMAIN, "GetFeature", data, datasz); + return TRUE; +} + +gboolean +fu_wacom_device_cmd (FuWacomDevice *self, + FuWacomRawRequest *req, FuWacomRawResponse *rsp, + gulong delay_us, FuWacomDeviceCmdFlags flags, + GError **error) +{ + req->report_id = FU_WACOM_RAW_BL_REPORT_ID_SET; + if (!fu_wacom_device_set_feature (self, (const guint8 *)req, sizeof(*req), error)) { + g_prefix_error (error, "failed to send: "); + return FALSE; + } + if (delay_us > 0) + g_usleep (delay_us); + rsp->report_id = FU_WACOM_RAW_BL_REPORT_ID_GET; + if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + if (flags & FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK) + return TRUE; + if (!fu_wacom_common_check_reply (req, rsp, error)) + return FALSE; + + /* wait for the command to complete */ + if (flags & FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING && + rsp->resp != FU_WACOM_RAW_RC_OK) { + for (guint i = 0; i < FU_WACOM_RAW_CMD_RETRIES; i++) { + if (delay_us > 0) + g_usleep (delay_us); + if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error)) + return FALSE; + if (!fu_wacom_common_check_reply (req, rsp, error)) + return FALSE; + if (rsp->resp != FU_WACOM_RAW_RC_IN_PROGRESS && + rsp->resp != FU_WACOM_RAW_RC_BUSY) + break; + } + } + return fu_wacom_common_rc_set_error (rsp, error); +} + +static gboolean +fu_wacom_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (g_strcmp0 (key, "WacomI2cFlashBlockSize") == 0) { + priv->flash_block_size = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "WacomI2cFlashBaseAddr") == 0) { + priv->flash_base_addr = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "WacomI2cFlashSize") == 0) { + priv->flash_size = fu_common_strtoull (value); + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_wacom_device_init (FuWacomDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); +} + +static void +fu_wacom_device_class_init (FuWacomDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); + klass_device->to_string = fu_wacom_device_to_string; + klass_device->open = fu_wacom_device_open; + klass_device->close = fu_wacom_device_close; + klass_device->write_firmware = fu_wacom_device_write_firmware; + klass_device->attach = fu_wacom_device_attach; + klass_device->detach = fu_wacom_device_detach; + klass_device->set_quirk_kv = fu_wacom_device_set_quirk_kv; + klass_device_udev->probe = fu_wacom_device_probe; +} diff --git a/plugins/wacom-raw/fu-wacom-device.h b/plugins/wacom-raw/fu-wacom-device.h new file mode 100644 index 000000000..383ceb3b7 --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-device.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_WACOM_DEVICE_H +#define __FU_WACOM_DEVICE_H + +#include "fu-wacom-common.h" +#include "fu-udev-device.h" +#include "dfu-element.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_DEVICE (fu_wacom_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuWacomDevice, fu_wacom_device, FU, WACOM_DEVICE, FuUdevDevice) + +struct _FuWacomDeviceClass +{ + FuUdevDeviceClass parent_class; + gboolean (*write_firmware) (FuDevice *self, + GPtrArray *chunks, + GError **error); +}; + +typedef enum { + FU_WACOM_DEVICE_CMD_FLAG_NONE = 0, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING = 1 << 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK = 1 << 1, +} FuWacomDeviceCmdFlags; + +gboolean fu_wacom_device_set_feature (FuWacomDevice *self, + const guint8 *data, + guint datasz, + GError **error); +gboolean fu_wacom_device_get_feature (FuWacomDevice *self, + guint8 *data, + guint datasz, + GError **error); +gboolean fu_wacom_device_cmd (FuWacomDevice *self, + FuWacomRawRequest *req, + FuWacomRawResponse *rsp, + gulong delay_us, + FuWacomDeviceCmdFlags flags, + GError **error); +gboolean fu_wacom_device_erase_all (FuWacomDevice *self, + GError **error); +gboolean fu_wacom_device_check_mpu (FuWacomDevice *self, + GError **error); +guint fu_wacom_device_get_block_sz (FuWacomDevice *self); +guint fu_wacom_device_get_base_addr (FuWacomDevice *self); + +G_END_DECLS + +#endif /* __FU_WACOM_DEVICE_H */ diff --git a/plugins/wacom-raw/fu-wacom-emr-device.c b/plugins/wacom-raw/fu-wacom-emr-device.c new file mode 100644 index 000000000..b554c4640 --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-emr-device.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-emr-device.h" + +struct _FuWacomEmrDevice { + FuWacomDevice parent_instance; +}; + +G_DEFINE_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU_TYPE_WACOM_DEVICE) + +static gboolean +fu_wacom_emr_device_setup (FuDevice *device, GError **error) +{ + FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device); + + /* check MPU type */ + if (!fu_wacom_device_check_mpu (FU_WACOM_DEVICE (self), error)) + return FALSE; + + /* get firmware version */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_set_version (device, "0.0"); + } else { + guint16 fw_ver; + guint8 data[19] = { 0x03, 0x0 }; /* 0x03 is an unknown ReportID */ + g_autofree gchar *version = NULL; + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + data, sizeof(data), error)) + return FALSE; + fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + version = fu_common_version_from_uint16 (fw_ver, FU_VERSION_FORMAT_PAIR); + fu_device_set_version (device, version); + } + + /* success */ + return TRUE; +} + +static guint8 +fu_wacom_emr_device_calc_checksum (guint8 init1, const guint8 *buf, guint8 bufsz) +{ + guint8 sum = 0; + sum += init1; + for (guint i = 0; i < bufsz; i++) + sum += buf[i]; + return ~sum + 1; +} + +static gboolean +fu_wacom_emr_device_w9013_erase_data (FuWacomEmrDevice *self, GError **error) +{ + FuWacomRawResponse rsp = { 0x00 }; + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + guint8 *buf = (guint8 *) &req.addr; + buf[0] = 0x00; /* erased block */ + buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00, + (const guint8 *) &req, 4); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to erase datamem: "); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_emr_device_w9013_erase_code (FuWacomEmrDevice *self, + guint8 idx, + guint8 block_nr, + GError **error) +{ + FuWacomRawResponse rsp = { 0x00 }; + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ERASE_FLASH, + .echo = idx, + 0x00 + }; + guint8 *buf = (guint8 *) &req.addr; + buf[0] = block_nr; + buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00, + (const guint8 *) &req, 4); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to erase codemem: "); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_device_w9021_erase_all (FuWacomEmrDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE, + .echo = 0x01, + .addr = 0x00, + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, + 2000 * 1000, /* this takes a long time */ + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to send eraseall command: "); + return FALSE; + } + if (!fu_wacom_common_rc_set_error (&rsp, error)) { + g_prefix_error (error, "failed to erase"); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_emr_device_write_block (FuWacomEmrDevice *self, + guint32 idx, + guint32 address, + const guint8 *data, + guint16 datasz, + GError **error) +{ + guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self)); + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH, + .echo = (guint8) idx + 1, + .addr = GUINT32_TO_LE(address), + .size8 = datasz / 8, + .data = { 0x00 }, + }; + FuWacomRawResponse rsp = { 0x00 }; + + /* check size */ + if (datasz > sizeof(req.data)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "data size 0x%x too large for packet", + datasz); + return FALSE; + } + if (datasz != blocksz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "block size 0x%x != 0x%x untested", + datasz, (guint) blocksz); + return FALSE; + } + + /* data */ + memcpy (&req.data, data, datasz); + + /* cmd and data checksums */ + req.data[blocksz + 0] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x4c + 0x00, + (const guint8 *) &req, 8); + req.data[blocksz + 1] = fu_wacom_emr_device_calc_checksum (0x00, data, datasz); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) { + g_prefix_error (error, "failed to write at 0x%x: ", address); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_emr_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error) +{ + FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device); + guint8 idx = 0; + + /* erase W9013 */ + if (fu_device_has_guid (device, "WacomEMR_W9013")) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wacom_emr_device_w9013_erase_data (self, error)) + return FALSE; + for (guint i = 127; i >= 8; i--) { + if (!fu_wacom_emr_device_w9013_erase_code (self, idx++, i, error)) + return FALSE; + } + } + + /* erase W9021 */ + if (fu_device_has_guid (device, "WacomEMR_W9021")) { + if (!fu_wacom_device_w9021_erase_all (self, error)) + return FALSE; + } + + /* write */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (fu_wacom_common_block_is_empty (chk->data, chk->data_sz)) + continue; + if (!fu_wacom_emr_device_write_block (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + fu_device_set_progress (device, 100); + return TRUE; +} + +static void +fu_wacom_emr_device_init (FuWacomEmrDevice *self) +{ + fu_device_set_name (FU_DEVICE (self), "Embedded Wacom EMR Device"); +} + +static void +fu_wacom_emr_device_class_init (FuWacomEmrDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass); + klass_device->setup = fu_wacom_emr_device_setup; + klass_wac_device->write_firmware = fu_wacom_emr_device_write_firmware; +} + +FuWacomEmrDevice * +fu_wacom_emr_device_new (FuUdevDevice *device) +{ + FuWacomEmrDevice *self = g_object_new (FU_TYPE_WACOM_EMR_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff --git a/plugins/wacom-raw/fu-wacom-emr-device.h b/plugins/wacom-raw/fu-wacom-emr-device.h new file mode 100644 index 000000000..6a7cc35be --- /dev/null +++ b/plugins/wacom-raw/fu-wacom-emr-device.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_WACOM_EMR_DEVICE_H +#define __FU_WACOM_EMR_DEVICE_H + +#include "fu-wacom-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_EMR_DEVICE (fu_wacom_emr_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU, WACOM_EMR_DEVICE, FuUdevDevice) + +FuWacomEmrDevice *fu_wacom_emr_device_new (FuUdevDevice *device); + +G_END_DECLS + +#endif /* __FU_WACOM_EMR_DEVICE_H */ diff --git a/plugins/wacom-raw/meson.build b/plugins/wacom-raw/meson.build new file mode 100644 index 000000000..ec0b63f70 --- /dev/null +++ b/plugins/wacom-raw/meson.build @@ -0,0 +1,31 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginWacomRaw"'] + +install_data(['wacom-raw.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_wacom_raw', + fu_hash, + sources : [ + 'fu-plugin-wacom-raw.c', + 'fu-wacom-common.c', + 'fu-wacom-device.c', + 'fu-wacom-aes-device.c', + 'fu-wacom-emr-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../dfu'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], + link_with : [ + dfu, + ], +) diff --git a/plugins/wacom-raw/wacom-raw.quirk b/plugins/wacom-raw/wacom-raw.quirk new file mode 100644 index 000000000..51ceee1a8 --- /dev/null +++ b/plugins/wacom-raw/wacom-raw.quirk @@ -0,0 +1,35 @@ +# Devices that do "replug" and thus don't change VID:PID to the bootloader +# need to have an extra GUID of WacomAES or WacomEMR added so that the flash +# constants are set correctly. + +# Dell XPS-15 9575 +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4875] +Plugin = wacom_raw +Guid = WacomAES + +# AES bootloader mode +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_0094] +Plugin = wacom_raw +Guid = WacomAES +Flags = is-bootloader + +# EMR bootloader mode +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_012B] +Plugin = wacom_raw +Guid = WacomEMR +Flags = is-bootloader + +[Guid=WacomEMR_W9013] +WacomI2cFlashBlockSize=64 +WacomI2cFlashBaseAddr=0x2000 +WacomI2cFlashSize=0x1e000 + +[Guid=WacomEMR_W9021] +WacomI2cFlashBlockSize=256 +WacomI2cFlashBaseAddr=0x3000 +WacomI2cFlashSize=0x3c000 + +[Guid=WacomAES] +WacomI2cFlashBlockSize=128 +WacomI2cFlashBaseAddr=0x8000 +WacomI2cFlashSize=0x24000 From d6e453b0ba46f0a0826a07f7a77600ea919cd2e8 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 11 Jan 2019 08:42:52 -0600 Subject: [PATCH 204/254] dell-dock: Add support for flashing Thunderbolt over I2C This uses an API in the Realtek USB 3.1G2 controller to perform the flash procedure. --- plugins/dell-dock/dell-dock.quirk | 5 + plugins/dell-dock/fu-dell-dock-common.h | 1 + plugins/dell-dock/fu-dell-dock-hid.c | 160 +++++++++++ plugins/dell-dock/fu-dell-dock-hid.h | 15 + plugins/dell-dock/fu-dell-dock-i2c-ec.c | 26 +- plugins/dell-dock/fu-dell-dock-i2c-ec.h | 2 +- plugins/dell-dock/fu-dell-dock-i2c-tbt.c | 295 ++++++++++++++++++++ plugins/dell-dock/fu-dell-dock-i2c-tbt.h | 34 +++ plugins/dell-dock/fu-plugin-dell-dock.c | 10 + plugins/dell-dock/meson.build | 1 + plugins/thunderbolt/fu-plugin-thunderbolt.c | 3 + 11 files changed, 548 insertions(+), 4 deletions(-) create mode 100644 plugins/dell-dock/fu-dell-dock-i2c-tbt.c create mode 100644 plugins/dell-dock/fu-dell-dock-i2c-tbt.h diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk index 199d430f7..2bd2f23c9 100644 --- a/plugins/dell-dock/dell-dock.quirk +++ b/plugins/dell-dock/dell-dock.quirk @@ -114,3 +114,8 @@ FirmwareSizeMin=0x40000 FirmwareSizeMax=0x80000 Flags = require-ac InstallDuration = 22 +DellDockInstallDurationI2C = 181 +DellDockUnlockTarget = 10 +DellDockHubVersionLowest = 1.31 +DellDockBlobMajorOffset = 0x400a +DellDockBlobMinorOffset = 0x4009 diff --git a/plugins/dell-dock/fu-dell-dock-common.h b/plugins/dell-dock/fu-dell-dock-common.h index 8f132b5a8..d809b0d43 100644 --- a/plugins/dell-dock/fu-dell-dock-common.h +++ b/plugins/dell-dock/fu-dell-dock-common.h @@ -21,6 +21,7 @@ #include "fu-device.h" #include "fu-dell-dock-i2c-ec.h" #include "fu-dell-dock-i2c-mst.h" +#include "fu-dell-dock-i2c-tbt.h" #include "fu-dell-dock-hub.h" #include "fu-dell-dock-hid.h" #include "fu-dell-dock-status.h" diff --git a/plugins/dell-dock/fu-dell-dock-hid.c b/plugins/dell-dock/fu-dell-dock-hid.c index 1dff057af..8cb17367a 100644 --- a/plugins/dell-dock/fu-dell-dock-hid.c +++ b/plugins/dell-dock/fu-dell-dock-hid.c @@ -17,6 +17,7 @@ #include "config.h" #include +#include #include "fu-usb-device.h" #include "fwupd-error.h" @@ -25,6 +26,7 @@ #define HIDI2C_MAX_REGISTER 4 #define HID_MAX_RETRIES 5 +#define TBT_MAX_RETRIES 2 #define HIDI2C_TRANSACTION_TIMEOUT 2000 #define HUB_CMD_READ_DATA 0xC0 @@ -36,6 +38,11 @@ #define HUB_EXT_I2C_READ 0xD6 #define HUB_EXT_VERIFYUPDATE 0xD9 #define HUB_EXT_ERASEBANK 0xE8 +#define HUB_EXT_WRITE_TBT_FLASH 0xFF + +#define TBT_COMMAND_WAKEUP 0x00000000 +#define TBT_COMMAND_AUTHENTICATE 0xFFFFFFFF +#define TBT_COMMAND_AUTHENTICATE_STATUS 0xFFFFFFFE typedef struct __attribute__ ((packed)) { guint8 cmd; @@ -55,6 +62,20 @@ typedef struct __attribute__ ((packed)) { guint8 data[192]; } FuHIDCmdBuffer; +typedef struct __attribute__ ((packed)) { + guint8 cmd; + guint8 ext; + guint8 i2cslaveaddr; + guint8 i2cspeed; + union { + guint32 startaddress; + guint32 tbt_command; + }; + guint8 bufferlen; + guint8 extended_cmdarea[55]; + guint8 data[192]; +} FuTbtCmdBuffer; + static gboolean fu_dell_dock_hid_set_report (FuDevice *self, guint8 *outbuffer, @@ -374,3 +395,142 @@ fu_dell_dock_hid_i2c_read (FuDevice *self, return TRUE; } + +gboolean +fu_dell_dock_hid_tbt_wake (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .tbt_command = TBT_COMMAND_WAKEUP, + .bufferlen = 0, + .extended_cmdarea[0 ... 53] = 0, + .data[0 ... 191] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to set wake thunderbolt: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get wake thunderbolt status: "); + return FALSE; + } + g_debug ("thunderbolt wake result: 0x%x", cmd_buffer.data[1]); + + return TRUE; +} + +static const gchar * +fu_dell_dock_hid_tbt_map_error (guint32 code) +{ + if (code == 1) + return g_strerror (EINVAL); + else if (code == 2) + return g_strerror (EPERM); + + return g_strerror (EIO); +} + +gboolean +fu_dell_dock_hid_tbt_write (FuDevice *self, + guint32 start_addr, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .startaddress = GUINT32_TO_LE (start_addr), + .bufferlen = write_size, + .extended_cmdarea[0 ... 53] = 0, + }; + guint8 result; + + g_return_val_if_fail (input != NULL, FALSE); + g_return_val_if_fail (write_size <= HIDI2C_MAX_WRITE, FALSE); + + memcpy (cmd_buffer.data, input, write_size); + + for (gint i = 1; i <= TBT_MAX_RETRIES; i++) { + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to run TBT update: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get TBT flash status: "); + return FALSE; + } + result = cmd_buffer.data[1] & 0xf; + if (result == 0) + break; + g_debug ("attempt %d/%d: Thunderbolt write failed: %x", + i, TBT_MAX_RETRIES, result); + } + if (result != 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Writing address 0x%04x failed: %s", + start_addr, fu_dell_dock_hid_tbt_map_error (result)); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_tbt_authenticate (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE), + .bufferlen = 0, + .extended_cmdarea[0 ... 53] = 0, + }; + guint8 result; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to send authentication: "); + return FALSE; + } + + cmd_buffer.tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE_STATUS); + /* needs at least 2 seconds */ + g_usleep (2000000); + for (gint i = 1; i <= TBT_MAX_RETRIES; i++) { + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to set check authentication: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get check authentication: "); + return FALSE; + } + result = cmd_buffer.data[1] & 0xf; + if (result == 0) + break; + g_debug ("attempt %d/%d: Thunderbolt authenticate failed: %x", + i, TBT_MAX_RETRIES, result); + g_usleep (500000); + } + if (result != 0) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Thunderbolt authentication failed: %s", + fu_dell_dock_hid_tbt_map_error (result)); + return FALSE; + } + + return TRUE; +} diff --git a/plugins/dell-dock/fu-dell-dock-hid.h b/plugins/dell-dock/fu-dell-dock-hid.h index c732f5992..f69936820 100644 --- a/plugins/dell-dock/fu-dell-dock-hid.h +++ b/plugins/dell-dock/fu-dell-dock-hid.h @@ -78,4 +78,19 @@ gboolean fu_dell_dock_hid_verify_update (FuDevice *self, gboolean *result, GError **error); +gboolean fu_dell_dock_hid_tbt_wake (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_tbt_write (FuDevice *self, + guint32 start_addr, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_tbt_authenticate (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error); + #endif /* __FU_DELL_DOCK_HID_H */ diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index 5c3f95e67..c71266371 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -37,6 +37,11 @@ #define EXPECTED_DOCK_INFO_SIZE 0xb7 #define EXPECTED_DOCK_TYPE 0x04 +#define TBT_MODE_MASK 0x01 + +#define BIT_SET(x,y) (x |= (1<data->port0_dock_status & TBT_MODE_MASK; - return self->data->module_type == MODULE_TYPE_TBT; + /* check for TBT module type */ + if (self->data->module_type != MODULE_TYPE_TBT) + return FALSE; + g_debug ("found thunderbolt dock, port mode: %d", port0_tbt_mode); + + return !port0_tbt_mode; } static const gchar* @@ -348,7 +360,8 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, device_entry[i].version.version_8[2], device_entry[i].version.version_8[3]); g_debug ("\tParsed version %s", self->mst_version); - } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_TBT && fu_dell_dock_ec_has_tbt (device)) { + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_TBT && + self->data->module_type == MODULE_TYPE_TBT) { /* guard against invalid Thunderbolt version read from EC */ if (!fu_dell_dock_test_valid_byte (device_entry[i].version.version_8, 2)) { g_warning ("[EC bug] EC read invalid Thunderbolt version %08x", @@ -504,6 +517,7 @@ fu_dell_dock_ec_modify_lock (FuDevice *device, gboolean unlocked, GError **error) { + FuDellDockEc *self = FU_DELL_DOCK_EC (device); guint32 cmd; g_return_val_if_fail (device != NULL, FALSE); @@ -524,6 +538,12 @@ fu_dell_dock_ec_modify_lock (FuDevice *device, fu_device_get_name (device), fu_device_get_id (device)); + if (unlocked) + BIT_SET (self->dock_unlock_status, target); + else + BIT_CLEAR (self->dock_unlock_status, target); + g_debug ("current overall unlock status: 0x%08x", self->dock_unlock_status); + return TRUE; } diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.h b/plugins/dell-dock/fu-dell-dock-i2c-ec.h index a76bcff52..123976946 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.h +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.h @@ -31,7 +31,7 @@ FuDellDockEc *fu_dell_dock_ec_new (FuDevice *symbiote); G_END_DECLS -gboolean fu_dell_dock_ec_has_tbt (FuDevice *device); +gboolean fu_dell_dock_ec_needs_tbt (FuDevice *device); gboolean fu_dell_dock_ec_modify_lock (FuDevice *self, guint8 target, gboolean unlocked, diff --git a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c new file mode 100644 index 000000000..e8696275c --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * Copyright (C) 2019 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fwupd-error.h" +#include "fu-device.h" +#include "fu-common.h" +#include "fu-common-version.h" + +#include "fu-dell-dock-common.h" + +#define I2C_TBT_ADDRESS 0xa2 + +const FuHIDI2CParameters tbt_base_settings = { + .i2cslaveaddr = I2C_TBT_ADDRESS, + .regaddrlen = 1, + .i2cspeed = I2C_SPEED_400K, +}; + +/* TR Device ID */ +#define PID_OFFSET 0x05 +#define INTEL_PID 0x15ef + +/* earlier versions have bugs */ +#define MIN_NVM "36.01" + +struct _FuDellDockTbt { + FuDevice parent_instance; + FuDevice *symbiote; + guint8 unlock_target; + guint64 blob_major_offset; + guint64 blob_minor_offset; + gchar *hub_minimum_version; +}; + +G_DEFINE_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU_TYPE_DEVICE) + +static gboolean +fu_dell_dock_tbt_write_fw (FuDevice *device, + GBytes *blob_fw, + GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + guint32 start_offset = 0; + gsize image_size; + const guint8 *buffer = g_bytes_get_data (blob_fw, &image_size); + guint16 target_system = 0; + g_autoptr(GTimer) timer = g_timer_new (); + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + dynamic_version = g_strdup_printf ("%02x.%02x", + buffer[self->blob_major_offset], + buffer[self->blob_minor_offset]); + g_debug ("writing Thunderbolt firmware version %s", dynamic_version); + g_debug ("Total Image size: %" G_GSIZE_FORMAT, image_size); + + memcpy (&start_offset, buffer, sizeof (guint32)); + g_debug ("Header size 0x%x", start_offset); + if (start_offset > image_size) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Image header is too big (0x%x)", + start_offset); + return FALSE; + } + + memcpy (&target_system, buffer + start_offset + PID_OFFSET, sizeof (guint16)); + if (target_system != INTEL_PID) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Image is not intended for this system (0x%x)", + target_system); + return FALSE; + } + + buffer += start_offset; + image_size -= start_offset; + + g_debug ("waking Thunderbolt controller"); + if (!fu_dell_dock_hid_tbt_wake (self->symbiote, &tbt_base_settings, error)) + return FALSE; + g_usleep (2000000); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < image_size; i+= HIDI2C_MAX_WRITE, buffer += HIDI2C_MAX_WRITE) { + guint8 write_size = (image_size - i) > HIDI2C_MAX_WRITE ? + HIDI2C_MAX_WRITE : (image_size - i); + + if (!fu_dell_dock_hid_tbt_write (self->symbiote, + i, + buffer, + write_size, + &tbt_base_settings, + error)) + return FALSE; + + fu_device_set_progress_full (device, i, image_size); + } + g_debug ("writing took %f seconds", + g_timer_elapsed (timer, NULL)); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + + if (fu_device_has_custom_flag (device, "skip-restart")) { + g_debug ("skipping TBT reset per quirk request"); + } else if (!fu_dell_dock_hid_tbt_authenticate (self->symbiote, + &tbt_base_settings, + error)) { + g_prefix_error (error, "failed to authenticate: "); + return FALSE; + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } else if (g_strcmp0 (key, "DellDockInstallDurationI2C") == 0) { + guint64 tmp = fu_common_strtoull (value); + fu_device_set_install_duration (device, tmp); + return TRUE; + } else if (g_strcmp0 (key, "DellDockHubVersionLowest") == 0) { + self->hub_minimum_version = g_strdup (value); + return TRUE; + } else if (g_strcmp0 (key, "DellDockBlobMajorOffset") == 0) { + self->blob_major_offset = fu_common_strtoull (value); + return TRUE; + } else if (g_strcmp0 (key, "DellDockBlobMinorOffset") == 0) { + self->blob_minor_offset = fu_common_strtoull (value); + return TRUE; + } + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + + +static gboolean +fu_dell_dock_tbt_setup (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + FuDevice *parent; + const gchar *version; + const gchar *hub_version; + + /* set version from EC if we know it */ + parent = fu_device_get_parent (device); + version = fu_dell_dock_ec_get_tbt_version (parent); + + if (version != NULL) + fu_device_set_version (device, version); + + /* minimum version of NVM that supports this feature */ + if (version == NULL || fu_common_vercmp (version, MIN_NVM) < 0) { + fu_device_set_update_error (device, + "Updates over I2C are disabled due to insuffient NVM version"); + return TRUE; + } + /* minimum Hub2 version that supports this feature */ + hub_version = fu_device_get_version (self->symbiote); + if (fu_common_vercmp (hub_version, self->hub_minimum_version) < 0) { + fu_device_set_update_error (device, + "Updates over I2C are disabled due to insufficient USB 3.1 G2 hub version"); + return TRUE; + } + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_probe (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + fu_device_set_physical_id (device, fu_device_get_physical_id (parent)); + fu_device_set_logical_id (FU_DEVICE (device), "tbt"); + fu_device_add_guid (device, DELL_DOCK_TBT_GUID); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_open (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + FuDevice *parent; + + g_return_val_if_fail (self->unlock_target != 0, FALSE); + + parent = fu_device_get_parent (device); + if (parent == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no parent"); + return FALSE; + } + + if (self->symbiote == NULL) + self->symbiote = g_object_ref (fu_dell_dock_ec_get_symbiote (parent)); + + if (!fu_device_open (self->symbiote, error)) + return FALSE; + + /* adjust to access controller */ + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_close (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + + /* adjust to access controller */ + if (!fu_dell_dock_set_power (device, self->unlock_target, FALSE, error)) + return FALSE; + + return fu_device_close (self->symbiote, error); +} + +static void +fu_dell_dock_tbt_finalize (GObject *object) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (object); + g_object_unref (self->symbiote); + g_free (self->hub_minimum_version); + + G_OBJECT_CLASS (fu_dell_dock_tbt_parent_class)->finalize (object); +} + +static void +fu_dell_dock_tbt_init (FuDellDockTbt *device) +{} + +static void +fu_dell_dock_tbt_class_init (FuDellDockTbtClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_tbt_finalize; + klass_device->probe = fu_dell_dock_tbt_probe; + klass_device->setup = fu_dell_dock_tbt_setup; + klass_device->open = fu_dell_dock_tbt_open; + klass_device->close = fu_dell_dock_tbt_close; + klass_device->write_firmware = fu_dell_dock_tbt_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_tbt_set_quirk_kv; +} + +FuDellDockTbt * +fu_dell_dock_tbt_new (void) +{ + FuDellDockTbt *device = NULL; + device = g_object_new (FU_TYPE_DELL_DOCK_TBT, NULL); + return device; +} diff --git a/plugins/dell-dock/fu-dell-dock-i2c-tbt.h b/plugins/dell-dock/fu-dell-dock-i2c-tbt.h new file mode 100644 index 000000000..62f91c0bd --- /dev/null +++ b/plugins/dell-dock/fu-dell-dock-i2c-tbt.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * Copyright (C) 2019 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#ifndef __FU_DELLDOCK_I2C_TBT_H +#define __FU_DELLDOCK_I2C_TBT_H + +#include "config.h" + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_TBT (fu_dell_dock_tbt_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU, DELL_DOCK_TBT, FuDevice) + +FuDellDockTbt *fu_dell_dock_tbt_new (void); + +G_END_DECLS + + +#endif /* __FU_DELLDOCK_I2C_TBT_H */ diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index 6992add1a..9576f412b 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -68,6 +68,16 @@ fu_plugin_dell_dock_probe (FuPlugin *plugin, error)) return FALSE; + /* create TBT endpoint if Thunderbolt SKU and Thunderbolt link inactive */ + if (fu_dell_dock_ec_needs_tbt (FU_DEVICE (ec_device))) { + g_autoptr(FuDellDockTbt) tbt_device = fu_dell_dock_tbt_new (); + fu_device_add_child (FU_DEVICE (ec_device), FU_DEVICE (tbt_device)); + if (!fu_plugin_dell_dock_create_node (plugin, + FU_DEVICE (tbt_device), + error)) + return FALSE; + } + return TRUE; } diff --git a/plugins/dell-dock/meson.build b/plugins/dell-dock/meson.build index 9e719680a..0f00003d3 100644 --- a/plugins/dell-dock/meson.build +++ b/plugins/dell-dock/meson.build @@ -13,6 +13,7 @@ shared_module('fu_plugin_dell_dock', 'fu-dell-dock-status.c', 'fu-dell-dock-i2c-ec.c', 'fu-dell-dock-hub.c', + 'fu-dell-dock-i2c-tbt.c', 'fu-dell-dock-i2c-mst.c' ], include_directories : [ diff --git a/plugins/thunderbolt/fu-plugin-thunderbolt.c b/plugins/thunderbolt/fu-plugin-thunderbolt.c index 3fa0613ce..81d545447 100644 --- a/plugins/thunderbolt/fu-plugin-thunderbolt.c +++ b/plugins/thunderbolt/fu-plugin-thunderbolt.c @@ -590,6 +590,9 @@ fu_plugin_init (FuPlugin *plugin) data->udev = g_udev_client_new (subsystems); g_signal_connect (data->udev, "uevent", G_CALLBACK (udev_uevent_cb), plugin); + + /* dell-dock plugin uses a slower bus for flashing */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } void From 654b5830310e1e0fa5699a91a99d29f9568ae79c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 24 Jan 2019 10:35:53 -0600 Subject: [PATCH 205/254] trivial: dell-dock: Correct a left shift error in `BIT_CLEAR` macro --- plugins/dell-dock/fu-dell-dock-i2c-ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index c71266371..b4319cd2e 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -40,7 +40,7 @@ #define TBT_MODE_MASK 0x01 #define BIT_SET(x,y) (x |= (1< Date: Fri, 25 Jan 2019 09:49:34 +0000 Subject: [PATCH 206/254] nitrokey: Correct Nitrokey Storage invalid firmware version read Currently used structures were based on early libnitrokey definitions (which were broken for some time). Corrected their sizes and elements, and added tests. Fixes #960 Signed-off-by: Richard Hughes --- plugins/nitrokey/fu-nitrokey-common.h | 50 ++++++++++++++++++++++++ plugins/nitrokey/fu-nitrokey-device.c | 54 +------------------------- plugins/nitrokey/fu-self-test.c | 55 +++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 52 deletions(-) diff --git a/plugins/nitrokey/fu-nitrokey-common.h b/plugins/nitrokey/fu-nitrokey-common.h index 44b944ae4..894e1ba83 100644 --- a/plugins/nitrokey/fu-nitrokey-common.h +++ b/plugins/nitrokey/fu-nitrokey-common.h @@ -14,6 +14,56 @@ G_BEGIN_DECLS guint32 fu_nitrokey_perform_crc32 (const guint8 *data, gsize size); +#define NITROKEY_TRANSACTION_TIMEOUT 100 /* ms */ +#define NITROKEY_NR_RETRIES 5 + +#define NITROKEY_REQUEST_DATA_LENGTH 59 +#define NITROKEY_REPLY_DATA_LENGTH 53 + +#define NITROKEY_CMD_GET_DEVICE_STATUS (0x20 + 14) + +typedef struct __attribute__((packed)) { + guint8 command; + guint8 payload[NITROKEY_REQUEST_DATA_LENGTH]; + guint32 crc; +} NitrokeyHidRequest; + +typedef struct __attribute__((packed)) { + guint8 device_status; + guint8 command_id; + guint32 last_command_crc; + guint8 last_command_status; + guint8 payload[NITROKEY_REPLY_DATA_LENGTH]; + guint32 crc; +} NitrokeyHidResponse; + +/* based from libnitrokey/stick20_commands.h from libnitrokey v3.4.1 */ +typedef struct __attribute__((packed)) { + guint8 _padding[18]; /* stick20_commands.h:132 // 26 - 8 = 18 */ + guint8 SendCounter; + guint8 SendDataType; + guint8 FollowBytesFlag; + guint8 SendSize; + guint16 MagicNumber_StickConfig; + guint8 ReadWriteFlagUncryptedVolume; + guint8 ReadWriteFlagCryptedVolume; + guint8 VersionMajor; + guint8 VersionMinor; + guint8 VersionReservedByte; + guint8 VersionBuildIteration; + guint8 ReadWriteFlagHiddenVolume; + guint8 FirmwareLocked; + guint8 NewSDCardFound; + guint8 SDFillWithRandomChars; + guint32 ActiveSD_CardID; + guint8 VolumeActiceFlag; + guint8 NewSmartCardFound; + guint8 UserPwRetryCount; + guint8 AdminPwRetryCount; + guint32 ActiveSmartCardID; + guint8 StickKeysNotInitiated; +} NitrokeyGetDeviceStatusPayload; + G_END_DECLS #endif /* __FU_NITROKEY_COMMON_H */ diff --git a/plugins/nitrokey/fu-nitrokey-device.c b/plugins/nitrokey/fu-nitrokey-device.c index bc2848975..16860fa4b 100644 --- a/plugins/nitrokey/fu-nitrokey-device.c +++ b/plugins/nitrokey/fu-nitrokey-device.c @@ -13,56 +13,6 @@ G_DEFINE_TYPE (FuNitrokeyDevice, fu_nitrokey_device, FU_TYPE_USB_DEVICE) -#define NITROKEY_TRANSACTION_TIMEOUT 100 /* ms */ -#define NITROKEY_NR_RETRIES 5 - -#define NITROKEY_REQUEST_DATA_LENGTH 59 -#define NITROKEY_REPLY_DATA_LENGTH 53 - -#define NITROKEY_CMD_GET_DEVICE_STATUS (0x20 + 14) - -typedef struct __attribute__((packed)) { - guint8 command; - guint8 payload[NITROKEY_REQUEST_DATA_LENGTH]; - guint32 crc; -} NitrokeyHidRequest; - -typedef struct __attribute__((packed)) { - guint8 _padding; /* always zero */ - guint8 device_status; - guint32 last_command_crc; - guint8 last_command_status; - guint8 payload[NITROKEY_REPLY_DATA_LENGTH]; - guint32 crc; -} NitrokeyHidResponse; - -/* based from libnitrokey/stick20_commands.h */ -typedef struct __attribute__((packed)) { - guint8 _padding[24]; - guint8 SendCounter; - guint8 SendDataType; - guint8 FollowBytesFlag; - guint8 SendSize; - guint16 MagicNumber_StickConfig; - guint8 ReadWriteFlagUncryptedVolume; - guint8 ReadWriteFlagCryptedVolume; - guint8 VersionReserved1; - guint8 VersionMinor; - guint8 VersionReserved2; - guint8 VersionMajor; - guint8 ReadWriteFlagHiddenVolume; - guint8 FirmwareLocked; - guint8 NewSDCardFound; - guint8 SDFillWithRandomChars; - guint32 ActiveSD_CardID; - guint8 VolumeActiceFlag; - guint8 NewSmartCardFound; - guint8 UserPwRetryCount; - guint8 AdminPwRetryCount; - guint32 ActiveSmartCardID; - guint8 StickKeysNotInitiated; -} NitrokeyGetDeviceStatusPayload; - static void _dump_to_console (const gchar *title, const guint8 *buf, gsize buf_sz) { @@ -240,8 +190,8 @@ fu_nitrokey_device_setup (FuDevice *device, GError **error) return FALSE; } _dump_to_console ("payload", buf_reply, sizeof(buf_reply)); - memcpy (&payload, buf_reply, sizeof(buf_reply)); - version = g_strdup_printf ("%u.%u", payload.VersionMinor, payload.VersionMajor); + memcpy (&payload, buf_reply, sizeof(payload)); + version = g_strdup_printf ("%u.%u", payload.VersionMajor, payload.VersionMinor); fu_device_set_version (FU_DEVICE (device), version); /* success */ diff --git a/plugins/nitrokey/fu-self-test.c b/plugins/nitrokey/fu-self-test.c index acf0a3db0..dc28579f3 100644 --- a/plugins/nitrokey/fu-self-test.c +++ b/plugins/nitrokey/fu-self-test.c @@ -10,6 +10,59 @@ #include "fu-nitrokey-common.h" +static void +fu_nitrokey_version_test (void) +{ + /* use the Nitrokey Storage v0.53 status response for test, CRC 0xa2762d14 */ + NitrokeyGetDeviceStatusPayload payload; + NitrokeyHidResponse res; + guint32 crc_tmp; + /* 65 bytes of response from HIDAPI; first byte is always 0 */ + const guint8 buf[] = { + /*0x00,*/ + 0x00, 0x2e, 0xef, 0xc4, 0x9b, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1c, 0x18, 0x33, + 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x45, 0x24, 0xf1, 0x4c, 0x01, 0x00, + 0x03, 0x03, 0xc7, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2d, 0x76, + 0xa2 }; + + /* testing the whole path, as in fu_nitrokey_device_setup()*/ + memcpy (&res, buf, sizeof (buf)); + memcpy (&payload, &res.payload, sizeof (payload)); + + /* verify the version number */ + g_assert_cmpint (payload.VersionMajor, == , 0); + g_assert_cmpint (payload.VersionMinor, == , 53); + g_assert_cmpint (buf[34], == , payload.VersionMinor); + g_assert_cmpint (payload.VersionBuildIteration, == , 0); + + /* verify the response checksum */ + crc_tmp = fu_nitrokey_perform_crc32 (buf, sizeof (res) - 4); + g_assert_cmpint (GUINT32_FROM_LE (res.crc), == , crc_tmp); + +} + +static void +fu_nitrokey_version_test_static (void) +{ + /* use static response from numbered bytes, to make sure fields occupy + * expected bytes */ + NitrokeyGetDeviceStatusPayload payload; + NitrokeyHidResponse res; + + const guint8 buf[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + }; + memcpy (&res, buf, sizeof (buf)); + memcpy (&payload, &res.payload, sizeof (payload)); + g_assert_cmpint (payload.VersionMajor, == , 33); /* 0x1a */ + g_assert_cmpint (payload.VersionMinor, == , 34); /* 0x1b */ + g_assert_cmpint (buf[34], == , 34); +} + static void fu_nitrokey_func (void) { @@ -31,5 +84,7 @@ main (int argc, char **argv) /* tests go here */ g_test_add_func ("/fwupd/nitrokey", fu_nitrokey_func); + g_test_add_func ("/fwupd/nitrokey-version-static", fu_nitrokey_version_test_static); + g_test_add_func ("/fwupd/nitrokey-version", fu_nitrokey_version_test); return g_test_run (); } From 9ba9d8a98bf0e87019416014b27df2127b85f8d2 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Jan 2019 11:01:57 +0000 Subject: [PATCH 207/254] uefi: Use fwup_new0() to allocate the updates table array Although malloc probably works due to the page size, it's not the thing to use. --- plugins/uefi/efi/fwupdate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index 605b98fee..753247f60 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -669,7 +669,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) * so we can do multiple runs * 3) only select the ones from one type for the first go */ - updates = fwup_malloc0(FWUP_NUM_CAPSULE_UPDATES_MAX); + updates = fwup_new0(FWUP_UPDATE_TABLE *, FWUP_NUM_CAPSULE_UPDATES_MAX); if (updates == NULL) return EFI_OUT_OF_RESOURCES; rc = fwup_populate_update_table(updates, &n_updates); From 0a212fd1d6736863f86676be6e8f21d3f3b36553 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 25 Jan 2019 11:04:14 +0000 Subject: [PATCH 208/254] uefi: Add a trivial debugging statement to debug a UX capsule failure --- plugins/uefi/efi/fwupdate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/uefi/efi/fwupdate.c b/plugins/uefi/efi/fwupdate.c index 753247f60..5dd32729c 100644 --- a/plugins/uefi/efi/fwupdate.c +++ b/plugins/uefi/efi/fwupdate.c @@ -696,8 +696,10 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) if (EFI_ERROR(rc)) { /* ignore a failing UX capsule */ if (rc == EFI_UNSUPPORTED && - CompareGuid(&updates[i]->info->guid, &ux_capsule_guid) == 0) + CompareGuid(&updates[i]->info->guid, &ux_capsule_guid) == 0) { + fwup_debug(L"GOP unsuitable: %r", rc); continue; + } fwup_warning(L"Could not build update list: %r", rc); return rc; } From 51ddf18faa050ab36dc46c18eb9a811a74417c8e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Sat, 26 Jan 2019 00:31:58 -0600 Subject: [PATCH 209/254] When generating a CAB Silo use the prefix "components" This makes fu_engine_get_details use a more standard prefix. --- src/fu-common-cab.c | 6 ++++-- src/fu-engine.c | 6 +++--- src/fu-main.c | 2 +- src/fu-self-test.c | 14 +++++++------- src/fu-tool.c | 2 +- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/fu-common-cab.c b/src/fu-common-cab.c index c755b9b05..22c7f7491 100644 --- a/src/fu-common-cab.c +++ b/src/fu-common-cab.c @@ -187,6 +187,9 @@ fu_common_store_from_cab_file (XbBuilder *builder, GCabCabinet *cabinet, g_autoptr(GError) error_local = NULL; g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + /* rewrite to be under a components root */ + xb_builder_source_set_prefix (source, "components"); + /* parse file */ #ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); @@ -440,8 +443,7 @@ fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) if (silo == NULL) return NULL; - /* this looks weird, but metainfo files have no node */ - components = xb_silo_query (silo, "component", 0, &error_local); + components = xb_silo_query (silo, "components/component", 0, &error_local); if (components == NULL) { g_set_error (error, FWUPD_ERROR, diff --git a/src/fu-engine.c b/src/fu-engine.c index a262e01d0..0a00c3810 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -2250,7 +2250,7 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) silo = fu_engine_get_silo_from_blob (self, blob, error); if (silo == NULL) return NULL; - components = xb_silo_query (silo, "component", 0, &error_local); + components = xb_silo_query (silo, "components/component", 0, &error_local); if (components == NULL) { g_set_error (error, FWUPD_ERROR, @@ -2261,10 +2261,10 @@ fu_engine_get_details (FuEngine *self, gint fd, GError **error) } /* build the index */ - if (!xb_silo_query_build_index (silo, "component/provides/firmware", + if (!xb_silo_query_build_index (silo, "components/component/provides/firmware", "type", error)) return FALSE; - if (!xb_silo_query_build_index (silo, "component/provides/firmware", + if (!xb_silo_query_build_index (silo, "components/component/provides/firmware", NULL, error)) return FALSE; diff --git a/src/fu-main.c b/src/fu-main.c index 0a2b9dae4..9c40f8484 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -599,7 +599,7 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) return FALSE; /* for each component in the silo */ - components = xb_silo_query (helper->silo, "component", 0, error); + components = xb_silo_query (helper->silo, "components/component", 0, error); if (components == NULL) return FALSE; helper->action_ids = g_ptr_array_new_with_free_func (g_free); diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 7a28a33e6..274272ea5 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -591,7 +591,7 @@ fu_engine_require_hwid_func (void) fu_engine_add_device (engine, device); /* get component */ - component = xb_silo_query_first (silo, "component/id[text()='com.hughski.test.firmware']/..", &error); + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); @@ -896,7 +896,7 @@ fu_engine_history_func (void) g_assert_nonnull (silo); /* get component */ - component = xb_silo_query_first (silo, "component/id[text()='com.hughski.test.firmware']/..", &error); + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); @@ -1023,7 +1023,7 @@ fu_engine_history_error_func (void) silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); g_assert_nonnull (silo); - component = xb_silo_query_first (silo, "component/id[text()='com.hughski.test.firmware']/..", &error); + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); task = fu_install_task_new (device, component); @@ -2595,7 +2595,7 @@ fu_plugin_composite_func (void) silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); g_assert_nonnull (silo); - components = xb_silo_query (silo, "component", 0, &error); + components = xb_silo_query (silo, "components/component", 0, &error); g_assert_no_error (error); g_assert_nonnull (components); g_assert_cmpint (components->len, ==, 3); @@ -2742,7 +2742,7 @@ fu_common_store_cab_func (void) g_assert_nonnull (silo); /* verify */ - component = xb_silo_query_first (silo, "component/id[text()='com.acme.example.firmware']/..", &error); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); rel = xb_node_query_first (component, "releases/release", &error); @@ -2792,7 +2792,7 @@ fu_common_store_cab_unsigned_func (void) g_assert_nonnull (silo); /* verify */ - component = xb_silo_query_first (silo, "component/id[text()='com.acme.example.firmware']/..", &error); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); rel = xb_node_query_first (component, "releases/release", &error); @@ -2837,7 +2837,7 @@ fu_common_store_cab_folder_func (void) g_assert_nonnull (silo); /* verify */ - component = xb_silo_query_first (silo, "component/id[text()='com.acme.example.firmware']/..", &error); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); g_assert_no_error (error); g_assert_nonnull (component); rel = xb_node_query_first (component, "releases/release", &error); diff --git a/src/fu-tool.c b/src/fu-tool.c index f4c0ffd69..a5f72fb0f 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -731,7 +731,7 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) silo = fu_engine_get_silo_from_blob (priv->engine, blob_cab, error); if (silo == NULL) return FALSE; - components = xb_silo_query (silo, "component", 0, error); + components = xb_silo_query (silo, "components/component", 0, error); if (components == NULL) return FALSE; From 9d3ec971f3eea0605deebadf02a6179b90f936a0 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 11:39:40 +0000 Subject: [PATCH 210/254] trivial: Never allow the content checksum filename to be NULL This prevents a critical warning from gcab_folder_get_file_by_name() --- src/fu-common-cab.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/fu-common-cab.c b/src/fu-common-cab.c index 22c7f7491..79e97b1f4 100644 --- a/src/fu-common-cab.c +++ b/src/fu-common-cab.c @@ -68,7 +68,7 @@ fu_common_store_from_cab_release (XbNode *release, GCabCabinet *cabinet, GError { GCabFile *cabfile; GBytes *blob; - const gchar *csum_filename; + const gchar *csum_filename = NULL; const gchar *suffixes[] = { "asc", "p7b", "p7c", NULL }; g_autofree gchar *basename = NULL; g_autofree gchar *release_key = NULL; @@ -77,14 +77,13 @@ fu_common_store_from_cab_release (XbNode *release, GCabCabinet *cabinet, GError /* ensure we always have a content checksum */ csum_tmp = xb_node_query_first (release, "checksum[@target='content']", NULL); - if (csum_tmp != NULL) { + if (csum_tmp != NULL) csum_filename = xb_node_get_attr (csum_tmp, "filename"); - } else { - /* if this isn't true, a firmware needs to set in - * the metainfo.xml file something like: - * */ + + /* if this isn't true, a firmware needs to set in the metainfo.xml file + * something like: */ + if (csum_filename == NULL) csum_filename = "firmware.bin"; - } /* get the main firmware file */ basename = g_path_get_basename (csum_filename); From 7185828163ffae15631422f23b07fa2a439bca72 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 26 Jan 2019 12:15:55 +0000 Subject: [PATCH 211/254] Add support for a per-release source and details URL The source URL allows us to comply with our various obligations when shipping firmware built from GPL licensed sources. The details URL allows vendors to include a link to a full HTML details page about the specific release. --- libfwupd/fwupd-enums-private.h | 2 + libfwupd/fwupd-release.c | 96 ++++++++++++++++++++++++++++++++++ libfwupd/fwupd-release.h | 6 +++ libfwupd/fwupd.map | 4 ++ src/fu-engine.c | 6 +++ 5 files changed, 114 insertions(+) diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index bb2b9afb3..b61f7aad0 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -20,6 +20,8 @@ #define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ #define FWUPD_RESULT_KEY_GUID "Guid" /* as */ #define FWUPD_RESULT_KEY_HOMEPAGE "Homepage" /* s */ +#define FWUPD_RESULT_KEY_DETAILS_URL "DetailsUrl" /* s */ +#define FWUPD_RESULT_KEY_SOURCE_URL "SourceUrl" /* s */ #define FWUPD_RESULT_KEY_ICON "Icon" /* as */ #define FWUPD_RESULT_KEY_LICENSE "License" /* s */ #define FWUPD_RESULT_KEY_MODIFIED "Modified" /* t */ diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index 70b998319..c36734c49 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -35,6 +35,8 @@ typedef struct { gchar *filename; gchar *protocol; gchar *homepage; + gchar *details_url; + gchar *source_url; gchar *appstream_id; gchar *license; gchar *name; @@ -393,6 +395,78 @@ fwupd_release_set_homepage (FwupdRelease *release, const gchar *homepage) priv->homepage = g_strdup (homepage); } +/** + * fwupd_release_get_details_url: + * @release: A #FwupdRelease + * + * Gets the URL for the online update notes. + * + * Returns: the update URL, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_details_url (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->details_url; +} + +/** + * fwupd_release_set_details_url: + * @release: A #FwupdRelease + * @details_url: the URL + * + * Sets the URL for the online update notes. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_details_url (FwupdRelease *release, const gchar *details_url) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->details_url); + priv->details_url = g_strdup (details_url); +} + +/** + * fwupd_release_get_source_url: + * @release: A #FwupdRelease + * + * Gets the URL of the source code used to build this release. + * + * Returns: the update source_url, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_source_url (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->source_url; +} + +/** + * fwupd_release_set_source_url: + * @release: A #FwupdRelease + * @source_url: the URL + * + * Sets the URL of the source code used to build this release. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_source_url (FwupdRelease *release, const gchar *source_url) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->source_url); + priv->source_url = g_strdup (source_url); +} + /** * fwupd_release_get_description: * @release: A #FwupdRelease @@ -828,6 +902,16 @@ fwupd_release_to_variant (FwupdRelease *release) FWUPD_RESULT_KEY_HOMEPAGE, g_variant_new_string (priv->homepage)); } + if (priv->details_url != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_DETAILS_URL, + g_variant_new_string (priv->details_url)); + } + if (priv->source_url != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_SOURCE_URL, + g_variant_new_string (priv->source_url)); + } if (priv->version != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_VERSION, @@ -911,6 +995,14 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant fwupd_release_set_homepage (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_DETAILS_URL) == 0) { + fwupd_release_set_details_url (release, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_SOURCE_URL) == 0) { + fwupd_release_set_source_url (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_VERSION) == 0) { fwupd_release_set_version (release, g_variant_get_string (value, NULL)); return; @@ -1024,6 +1116,8 @@ fwupd_release_to_string (FwupdRelease *release) fwupd_pad_kv_siz (str, FWUPD_RESULT_KEY_SIZE, priv->size); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, priv->uri); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR, priv->vendor); fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_TRUST_FLAGS, priv->trust_flags); fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); @@ -1069,6 +1163,8 @@ fwupd_release_finalize (GObject *object) g_free (priv->summary); g_free (priv->uri); g_free (priv->homepage); + g_free (priv->details_url); + g_free (priv->source_url); g_free (priv->vendor); g_free (priv->version); g_free (priv->remote_id); diff --git a/libfwupd/fwupd-release.h b/libfwupd/fwupd-release.h index 4823b8493..f698799b1 100644 --- a/libfwupd/fwupd-release.h +++ b/libfwupd/fwupd-release.h @@ -78,6 +78,12 @@ void fwupd_release_set_description (FwupdRelease *release, const gchar *fwupd_release_get_homepage (FwupdRelease *release); void fwupd_release_set_homepage (FwupdRelease *release, const gchar *homepage); +const gchar *fwupd_release_get_details_url (FwupdRelease *release); +void fwupd_release_set_details_url (FwupdRelease *release, + const gchar *details_url); +const gchar *fwupd_release_get_source_url (FwupdRelease *release); +void fwupd_release_set_source_url (FwupdRelease *release, + const gchar *source_url); guint64 fwupd_release_get_size (FwupdRelease *release); void fwupd_release_set_size (FwupdRelease *release, guint64 size); diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index 3bedb8cb7..ad053478e 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -297,5 +297,9 @@ LIBFWUPD_1.2.2 { LIBFWUPD_1.2.4 { global: fwupd_client_get_tainted; + fwupd_release_get_details_url; + fwupd_release_get_source_url; + fwupd_release_set_details_url; + fwupd_release_set_source_url; local: *; } LIBFWUPD_1.2.2; diff --git a/src/fu-engine.c b/src/fu-engine.c index 0a00c3810..d52b25e5a 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -308,6 +308,12 @@ fu_engine_set_release_from_appstream (FuEngine *self, 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); tmp = xb_node_query_text (release, "checksum[@target='container']", NULL); if (tmp != NULL) fwupd_release_add_checksum (rel, tmp); From 0af196151da47d31c3071f60b1bbbbac59369f9d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 12:19:05 +0000 Subject: [PATCH 212/254] Ensure cabinet archives always have a container checksum This means the correct hash is shown when using `fwupdtool get-details` and will be useful for future functionality. --- src/fu-common-cab.c | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/fu-common-cab.c b/src/fu-common-cab.c index 79e97b1f4..e1c747dee 100644 --- a/src/fu-common-cab.c +++ b/src/fu-common-cab.c @@ -325,6 +325,55 @@ fu_common_cab_sort_priority_cb (XbBuilderFixup *self, return TRUE; } +static XbBuilderNode * +_xb_builder_node_get_child_by_element_attr (XbBuilderNode *bn, + const gchar *element, + const gchar *attr_name, + const gchar *attr_value) +{ + GPtrArray *bcs = xb_builder_node_get_children (bn); + for (guint i = 0; i < bcs->len; i++) { + XbBuilderNode *bc = g_ptr_array_index (bcs, i); + if (g_strcmp0 (xb_builder_node_get_element (bc), element) != 0) + continue; + if (g_strcmp0 (xb_builder_node_get_attr (bc, "type"), "container") == 0) + return g_object_ref (bc); + } + return NULL; +} + +static gboolean +fu_common_cab_set_container_checksum_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + + const gchar *container_checksum = (const gchar *) user_data; + g_autoptr(XbBuilderNode) csum = NULL; + + /* not us */ + if (g_strcmp0 (xb_builder_node_get_element (bn), "release") != 0) + return TRUE; + + /* verify it exists */ + csum = _xb_builder_node_get_child_by_element_attr (bn, "checksum", + "target", "container"); + if (csum == NULL) { + csum = xb_builder_node_insert (bn, "checksum", + "target", "container", + NULL); + } + + /* verify it is correct */ + if (g_strcmp0 (xb_builder_node_get_text (csum), container_checksum) != 0) { + g_debug ("invalid container checksum %s, fixing up to %s", + xb_builder_node_get_text (csum), container_checksum); + xb_builder_node_set_text (csum, container_checksum, -1); + } + return TRUE; +} + /** * fu_common_cab_build_silo: * @blob: A readable blob @@ -344,6 +393,7 @@ fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) .error = NULL, }; GPtrArray *folders; + g_autofree gchar *container_checksum = NULL; #ifndef HAVE_GCAB_1_0 g_autofree gchar *tmp_path = NULL; g_autoptr(GFile) tmp_file = NULL; @@ -351,6 +401,7 @@ fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) g_autoptr(XbSilo) silo = NULL; g_autoptr(XbBuilder) builder = xb_builder_new (); g_autoptr(XbBuilderFixup) fixup = NULL; + g_autoptr(XbBuilderFixup) fixup2 = NULL; g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) ip = NULL; @@ -437,6 +488,13 @@ fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) return NULL; } + /* ensure the container checksum is always set */ + container_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + fixup2 = xb_builder_fixup_new ("SetContainerChecksum", + fu_common_cab_set_container_checksum_cb, + container_checksum, NULL); + xb_builder_add_fixup (builder, fixup2); + /* did we get any valid files */ silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); if (silo == NULL) From 09cbacd771da5debcc2e109063bee43f2b525a09 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 18 Dec 2018 09:32:10 +0000 Subject: [PATCH 213/254] trivial: Move Fedora CI to f29 We'll need this for some updated deps soon. --- contrib/PKGBUILD | 2 +- contrib/ci/Dockerfile-fedora.in | 3 +-- contrib/ci/Dockerfile-flatpak.in | 2 +- contrib/ci/dependencies.xml | 6 ++++-- contrib/ci/fedora.sh | 12 +++++++++++- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/contrib/PKGBUILD b/contrib/PKGBUILD index e004c72d5..013337491 100644 --- a/contrib/PKGBUILD +++ b/contrib/PKGBUILD @@ -17,7 +17,7 @@ makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow build() { cd ${pkgname} if [ -n "$CI" ]; then - export CI="--werror --wrap-mode=forcefallback" + export CI="--werror" fi arch-meson -D b_lto=false $CI ../build diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index 75f5434c1..9bd2d58f0 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -1,11 +1,10 @@ -FROM fedora:28 +FROM fedora:29 %%%OS%%% ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id RUN dnf --enablerepo=updates-testing -y update -RUN dnf install -y https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.5/1.fc29/x86_64/libxmlb-0.1.5-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/libxmlb/0.1.5/1.fc29/x86_64/libxmlb-devel-0.1.5-1.fc29.x86_64.rpm RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN mkdir /build diff --git a/contrib/ci/Dockerfile-flatpak.in b/contrib/ci/Dockerfile-flatpak.in index 21e2dd1d9..6c4969408 100644 --- a/contrib/ci/Dockerfile-flatpak.in +++ b/contrib/ci/Dockerfile-flatpak.in @@ -1,4 +1,4 @@ -FROM fedora:28 +FROM fedora:29 %%%OS%%% ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en diff --git a/contrib/ci/dependencies.xml b/contrib/ci/dependencies.xml index 1bb84c86b..e96cacdb7 100644 --- a/contrib/ci/dependencies.xml +++ b/contrib/ci/dependencies.xml @@ -542,17 +542,19 @@ - libxmlb-devel + + libarchive-devel diff --git a/contrib/ci/fedora.sh b/contrib/ci/fedora.sh index f3ab49df7..cb3d0a430 100755 --- a/contrib/ci/fedora.sh +++ b/contrib/ci/fedora.sh @@ -49,12 +49,22 @@ dnf install -y $HOME/rpmbuild/RPMS/*/*.rpm cp $HOME/rpmbuild/RPMS/*/*.rpm dist -# run the installed tests if [ "$CI" = "true" ]; then sed "s,^BlacklistPlugins=test,BlacklistPlugins=," -i /etc/fwupd/daemon.conf + + # set up enough PolicyKit and D-Bus to run the daemon mkdir -p /run/dbus mkdir -p /var ln -s /var/run /run dbus-daemon --system --fork + /usr/lib/polkit-1/polkitd & + sleep 5 + + # run the daemon startup to check it can start + /usr/libexec/fwupd/fwupd --immediate-exit --verbose + + # run the installed tests whilst the daemon debugging + /usr/libexec/fwupd/fwupd --verbose & + sleep 10 gnome-desktop-testing-runner fwupd fi From fd826c10a0e96c03e633b8b8e2ba853181e8bedd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 10:42:28 +0000 Subject: [PATCH 214/254] trivial: Print some debugging when ignoring a remote path --- src/fu-config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fu-config.c b/src/fu-config.c index 04e4e34fe..27eccfc42 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -170,8 +170,10 @@ fu_config_add_remotes_for_path (FuConfig *self, const gchar *path, GError **erro g_autoptr(GDir) dir = NULL; path_remotes = g_build_filename (path, "remotes.d", NULL); - if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS)) + if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS)) { + g_debug ("path %s does not exist", path_remotes); return TRUE; + } if (!fu_config_add_inotify (self, path_remotes, error)) return FALSE; dir = g_dir_open (path_remotes, 0, error); From 706ab438987e276e2fe22dc390f468d3bd10b344 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Sat, 26 Jan 2019 16:32:14 -0600 Subject: [PATCH 215/254] libfwupd: Add support for new remote type "directory" This remote will be used for automatically building metadata based on files in a directory. --- libfwupd/fwupd-remote.c | 40 +++++++++++++++++++++++++++++++--------- libfwupd/fwupd-remote.h | 1 + src/fu-tool.c | 3 ++- src/fu-util.c | 5 +++-- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index 1d40778af..a9675ce55 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -275,6 +275,8 @@ fwupd_remote_kind_from_string (const gchar *kind) return FWUPD_REMOTE_KIND_DOWNLOAD; if (g_strcmp0 (kind, "local") == 0) return FWUPD_REMOTE_KIND_LOCAL; + if (g_strcmp0 (kind, "directory") == 0) + return FWUPD_REMOTE_KIND_DIRECTORY; return FWUPD_REMOTE_KIND_UNKNOWN; } @@ -295,6 +297,8 @@ fwupd_remote_kind_to_string (FwupdRemoteKind kind) return "download"; if (kind == FWUPD_REMOTE_KIND_LOCAL) return "local"; + if (kind == FWUPD_REMOTE_KIND_DIRECTORY) + return "directory"; return NULL; } @@ -384,7 +388,14 @@ fwupd_remote_load_from_filename (FwupdRemote *self, if (metadata_uri == NULL) return FALSE; if (g_str_has_prefix (metadata_uri, "file://")) { - priv->kind = FWUPD_REMOTE_KIND_LOCAL; + const gchar *filename_cache = metadata_uri; + if (g_str_has_prefix (filename_cache, "file://")) + filename_cache += 7; + fwupd_remote_set_filename_cache (self, filename_cache); + if (g_file_test (filename_cache, G_FILE_TEST_IS_DIR)) + priv->kind = FWUPD_REMOTE_KIND_DIRECTORY; + else + priv->kind = FWUPD_REMOTE_KIND_LOCAL; } else if (g_str_has_prefix (metadata_uri, "http://") || g_str_has_prefix (metadata_uri, "https://")) { priv->kind = FWUPD_REMOTE_KIND_DOWNLOAD; @@ -444,14 +455,6 @@ fwupd_remote_load_from_filename (FwupdRemote *self, fwupd_remote_set_filename_cache (self, filename_cache); } - /* all LOCAL remotes have to include a valid MetadataURI */ - if (priv->kind == FWUPD_REMOTE_KIND_LOCAL) { - const gchar *filename_cache = metadata_uri; - if (g_str_has_prefix (filename_cache, "file://")) - filename_cache += 7; - fwupd_remote_set_filename_cache (self, filename_cache); - } - /* load the checksum */ if (priv->filename_cache_sig != NULL && g_file_test (priv->filename_cache_sig, G_FILE_TEST_EXISTS)) { @@ -473,6 +476,25 @@ fwupd_remote_load_from_filename (FwupdRemote *self, if (firmware_base_uri != NULL) fwupd_remote_set_firmware_base_uri (self, firmware_base_uri); + /* some validation around DIRECTORY types */ + if (priv->kind == FWUPD_REMOTE_KIND_DIRECTORY) { + if (priv->keyring_kind != FWUPD_KEYRING_KIND_NONE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Keyring kind %s is not supported with directory remote", + fwupd_keyring_kind_to_string (priv->keyring_kind)); + return FALSE; + } + if (firmware_base_uri != NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Directory remotes don't support firmware base URI"); + return FALSE; + } + } + /* dep logic */ order_before = g_key_file_get_string (kf, group, "OrderBefore", NULL); if (order_before != NULL) diff --git a/libfwupd/fwupd-remote.h b/libfwupd/fwupd-remote.h index 2d3c885fb..144d0c2a7 100644 --- a/libfwupd/fwupd-remote.h +++ b/libfwupd/fwupd-remote.h @@ -39,6 +39,7 @@ typedef enum { FWUPD_REMOTE_KIND_UNKNOWN, FWUPD_REMOTE_KIND_DOWNLOAD, FWUPD_REMOTE_KIND_LOCAL, + FWUPD_REMOTE_KIND_DIRECTORY, /* Since: 1.2.4 */ /*< private >*/ FWUPD_REMOTE_KIND_LAST } FwupdRemoteKind; diff --git a/src/fu-tool.c b/src/fu-tool.c index a5f72fb0f..b080d3819 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -846,7 +846,8 @@ fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) argv = g_new0 (gchar *, 2); /* local remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL || + fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); argv[0] = g_build_filename (path, uri_tmp, NULL); diff --git a/src/fu-util.c b/src/fu-util.c index 174661fb9..a68bb408b 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1972,8 +1972,9 @@ fu_util_update_device_with_release (FuUtilPrivate *priv, if (remote == NULL) return FALSE; - /* local remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + /* local and directory remotes have the firmware already */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL || + fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); From 4f24d0bae36c79719a0a42af2a40881c68df3746 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Sat, 26 Jan 2019 01:19:59 -0600 Subject: [PATCH 216/254] When using `directory` remote type automatically generate metadata The CAB files will be parsed upon `fwupd`/`fwupdtool` startup and loaded into the daemon. --- contrib/fwupd.spec.in | 1 + data/remotes.d/README.md | 16 +++- data/remotes.d/meson.build | 7 ++ data/remotes.d/vendor-directory.conf | 7 ++ data/remotes.d/vendor.conf | 3 +- data/tests/remotes.d/directory.conf | 4 + src/fu-engine.c | 108 +++++++++++++++++++++++++-- src/fu-engine.h | 2 + src/fu-self-test.c | 46 +++++++++++- src/fu-tool.c | 5 +- src/fu-util.c | 9 ++- 11 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 data/remotes.d/vendor-directory.conf create mode 100644 data/tests/remotes.d/directory.conf diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index f242438c1..b2354b5d6 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -228,6 +228,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/lvfs.conf %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/lvfs-testing.conf %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor.conf +%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor-directory.conf %config(noreplace)%{_sysconfdir}/pki/fwupd %{_sysconfdir}/pki/fwupd-metadata %{_sysconfdir}/dbus-1/system.d/org.freedesktop.fwupd.conf diff --git a/data/remotes.d/README.md b/data/remotes.d/README.md index 4571351d5..3a2791c2a 100644 --- a/data/remotes.d/README.md +++ b/data/remotes.d/README.md @@ -1,7 +1,7 @@ Vendor Firmware =============== -These are the steps to add vendor that is installed as part of an OSTree image: +These are the steps to add vendor firmware that is installed as part of an embedded image such as an OSTree or ChromeOS image: * Change `/etc/fwupd/remotes.d/vendor.conf` to have `Enabled=true` * Change `/etc/fwupd/remotes.d/vendor.conf` to have the correct `Title` @@ -39,6 +39,20 @@ certificate. If this is the case also change `Keyring=gpg` or `Keyring=pkcs7` in `/etc/fwupd/remotes.d/vendor.conf` and ensure the correct public key or signing certificate is installed in the `/etc/pki/fwupd` location. +Automatic metadata generation +============================= +`fwupd` and `fwupdtool` support automatically generating metadata for a remote +by configuring it to be a *directory* type. This is very convenient if you want to dynamically add firmware from multiple packages while generating the image but there are a few deficiencies: +* There will be a performance impact of starting the daemon or tool measured by O(# CAB files) +* It's not possible to verify metadata signature and any file validation should be part of the image validation. + +To enable this: +* Change `/etc/fwupd/remotes.d/vendor-directory.conf` to have `Enabled=true` +* Change `/etc/fwupd/remotes.d/vendor.conf-directory` to have the correct `Title` +* Deploy the firmware to `/usr/share/fwupd/remotes.d/vendor/firmware` +* Change `MetadataURI` to that of the directory (Eg `/usr/share/fwupd/remotes.d/vendor/`) + + Mirroring a Repository ====================== diff --git a/data/remotes.d/meson.build b/data/remotes.d/meson.build index 824291fc5..2e6b499db 100644 --- a/data/remotes.d/meson.build +++ b/data/remotes.d/meson.build @@ -46,3 +46,10 @@ configure_file( install: true, install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), ) +configure_file( + input : 'vendor-directory.conf', + output : 'vendor-directory.conf', + configuration : con2, + install: true, + install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), +) diff --git a/data/remotes.d/vendor-directory.conf b/data/remotes.d/vendor-directory.conf new file mode 100644 index 000000000..4a3f0eefc --- /dev/null +++ b/data/remotes.d/vendor-directory.conf @@ -0,0 +1,7 @@ +[fwupd Remote] +# this remote provides dynamically generated metadata shipped by the OS vendor and can +# be found in @datadir@/fwupd/remotes.d/vendor/firmware +Enabled=false +Title=Vendor (Automatic) +Keyring=none +MetadataURI=file://@datadir@/fwupd/remotes.d/vendor/firmware diff --git a/data/remotes.d/vendor.conf b/data/remotes.d/vendor.conf index 6cdf59cb7..e538b9722 100644 --- a/data/remotes.d/vendor.conf +++ b/data/remotes.d/vendor.conf @@ -1,7 +1,6 @@ [fwupd Remote] - # this remote provides metadata shipped by the OS vendor and can be found in -# /usr/share/fwupd/remotes.d/vendor and /usr/share/fwupd/remotes.d/vendor/firmware +# @datadir@/fwupd/remotes.d/vendor and firmware in @datadir@/fwupd/remotes.d/vendor/firmware Enabled=false Title=Vendor Keyring=none diff --git a/data/tests/remotes.d/directory.conf b/data/tests/remotes.d/directory.conf new file mode 100644 index 000000000..15feedb51 --- /dev/null +++ b/data/tests/remotes.d/directory.conf @@ -0,0 +1,4 @@ +[fwupd Remote] +Enabled=true +Keyring=none +MetadataURI=file:///tmp/fwupd-self-test/var/cache/fwupd diff --git a/src/fu-engine.c b/src/fu-engine.c index d52b25e5a..79598461c 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -304,6 +304,14 @@ fu_engine_set_release_from_appstream (FuEngine *self, if (uri == NULL) uri = g_strdup (tmp); fwupd_release_set_uri (rel, uri); + } else if (remote != NULL && + fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + g_autofree gchar *uri = NULL; + tmp = xb_node_query_text (component, "../custom/value[@key='fwupd::FilenameCache']", NULL); + if (tmp != NULL) { + uri = g_strdup_printf ("file://%s", tmp); + fwupd_release_set_uri (rel, uri); + } } tmp = xb_node_query_text (release, "checksum[@target='content']", NULL); if (tmp != NULL) @@ -628,8 +636,8 @@ fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error) return TRUE; } -static XbNode * -fu_engine_store_get_app_by_guids (XbSilo *silo, FuDevice *device) +XbNode * +fu_engine_get_component_by_guids (FuEngine *self, FuDevice *device) { GPtrArray *guids = fu_device_get_guids (device); g_autoptr(GString) xpath = g_string_new (NULL); @@ -641,7 +649,7 @@ fu_engine_store_get_app_by_guids (XbSilo *silo, FuDevice *device) "provides/firmware[@type='flashed'][text()='%s']/" "../..", guid); } - component = xb_silo_query_first (silo, xpath->str, NULL); + component = xb_silo_query_first (self->silo, xpath->str, NULL); if (component != NULL) return g_steal_pointer (&component); return NULL; @@ -1796,7 +1804,7 @@ fu_engine_is_device_supported (FuEngine *self, FuDevice *device) return FALSE; /* match the GUIDs in the XML */ - component = fu_engine_store_get_app_by_guids (self->silo, device); + component = fu_engine_get_component_by_guids (self, device); if (component == NULL) return FALSE; @@ -1815,6 +1823,84 @@ fu_engine_appstream_upgrade_cb (XbBuilderFixup *self, return TRUE; } +static XbBuilderSource * +fu_engine_create_metadata_builder_source (FuEngine *self, + const gchar *fn, + GError **error) +{ + g_autoptr(GBytes) blob = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autofree gchar *xml = NULL; + + g_debug ("building metadata for %s", fn); + blob = fu_common_get_contents_bytes (fn, error); + if (blob == NULL) + return NULL; + + /* convert the silo for the CAB into a XbBuilderSource */ + silo = fu_engine_get_silo_from_blob (self, blob, error); + if (silo == NULL) + return NULL; + xml = xb_silo_export (silo, XB_NODE_EXPORT_FLAG_NONE, error); + if (xml == NULL) + return NULL; + if (!xb_builder_source_load_xml (source, xml, + XB_BUILDER_SOURCE_FLAG_NONE, + error)) + return NULL; + return g_steal_pointer (&source); +} + +static gboolean +fu_engine_create_metadata (FuEngine *self, XbBuilder *builder, + FwupdRemote *remote, GError **error) +{ + g_autoptr(GPtrArray) files = NULL; + const gchar *path; + + /* find all files in directory */ + path = fwupd_remote_get_filename_cache (remote); + files = fu_common_get_files_recursive (path, error); + if (files == NULL) + return FALSE; + + /* add each source */ + for (guint i = 0; i < files->len; i++) { + g_autoptr(XbBuilderNode) custom = NULL; + g_autoptr(XbBuilderSource) source = NULL; + g_autoptr(GError) error_local = NULL; + const gchar *fn = g_ptr_array_index (files, i); + + /* check is cab file */ + if (!g_str_has_suffix (fn, ".cab")) { + g_debug ("ignoring: %s", fn); + continue; + } + + /* build source for file */ + source = fu_engine_create_metadata_builder_source (self, fn, &error_local); + if (source == NULL) { + g_warning ("%s", error_local->message); + continue; + } + + /* add metadata */ + custom = xb_builder_node_new ("custom"); + xb_builder_node_insert_text (custom, + "value", fn, + "key", "fwupd::FilenameCache", + NULL); + xb_builder_node_insert_text (custom, + "value", fwupd_remote_get_id (remote), + "key", "fwupd::RemoteId", + NULL); + xb_builder_source_set_info (source, custom); + xb_builder_import_source (builder, source); + } + return TRUE; +} + static gboolean fu_engine_load_metadata_store (FuEngine *self, GError **error) { @@ -1858,6 +1944,18 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error) continue; } + /* generate all metadata on demand */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + g_debug ("building metadata for remote '%s'", + fwupd_remote_get_id (remote)); + if (!fu_engine_create_metadata (self, builder, remote, &error_local)) { + g_warning ("failed to generate remote %s: %s", + fwupd_remote_get_id (remote), + error_local->message); + } + continue; + } + /* save the remote-id in the custom metadata space */ file = g_file_new_for_path (path); if (!xb_builder_source_load_file (source, file, @@ -3148,7 +3246,7 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) /* if this device is locked get some metadata from AppStream */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_LOCKED)) { - g_autoptr(XbNode) component = fu_engine_store_get_app_by_guids (self->silo, device); + g_autoptr(XbNode) component = fu_engine_get_component_by_guids (self, device); if (component != NULL) { g_autoptr(XbNode) release = NULL; release = xb_node_query_first (component, diff --git a/src/fu-engine.h b/src/fu-engine.h index a15d117d0..05388fd7d 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -129,6 +129,8 @@ gboolean fu_engine_check_requirements (FuEngine *self, GError **error); void fu_engine_set_silo (FuEngine *self, XbSilo *silo); +XbNode *fu_engine_get_component_by_guids (FuEngine *self, + FuDevice *device); G_END_DECLS diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 274272ea5..19423d5d2 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -73,6 +73,49 @@ fu_archive_invalid_func (void) g_assert_null (archive); } +static void +fu_engine_generate_md_func (void) +{ + const gchar *tmp; + gboolean ret; + g_autofree gchar *filename = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + + /* put cab file somewhere we can parse it */ + filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + ret = fu_common_set_contents_bytes ("/tmp/fwupd-self-test/var/cache/fwupd/foo.cab", + data, &error); + g_assert_no_error (error); + g_assert (ret); + + /* load engine and check the device was found */ + ret = fu_engine_load (engine, &error); + g_assert_no_error (error); + g_assert (ret); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_set_version (device, "1.2.3"); + component = fu_engine_get_component_by_guids (engine, device); + g_assert_nonnull (component); + + /* check remote ID set */ + tmp = xb_node_query_text (component, "../custom/value[@key='fwupd::RemoteId']", NULL); + g_assert_cmpstr (tmp, ==, "directory"); + + /* verify checksums */ + tmp = xb_node_query_text (component, "releases/release/checksum[@target='container']", NULL); + g_assert_cmpstr (tmp, !=, NULL); + tmp = xb_node_query_text (component, "releases/release/checksum[@target='content']", NULL); + g_assert_cmpstr (tmp, ==, NULL); +} + static void fu_archive_cab_func (void) { @@ -709,7 +752,7 @@ fu_engine_downgrade_func (void) remotes = fu_engine_get_remotes (engine, &error); g_assert_no_error (error); g_assert (remotes != NULL); - g_assert_cmpint (remotes->len, ==, 3); + g_assert_cmpint (remotes->len, ==, 4); /* ensure there are no devices already */ devices_pre = fu_engine_get_devices (engine, &error); @@ -3316,6 +3359,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/engine{device-auto-parent}", fu_engine_device_parent_func); g_test_add_func ("/fwupd/engine{device-priority}", fu_engine_device_priority_func); g_test_add_func ("/fwupd/engine{install-duration}", fu_engine_install_duration_func); + g_test_add_func ("/fwupd/engine{generate-md}", fu_engine_generate_md_func); g_test_add_func ("/fwupd/hwids", fu_hwids_func); g_test_add_func ("/fwupd/smbios", fu_smbios_func); g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); diff --git a/src/fu-tool.c b/src/fu-tool.c index b080d3819..15c0ec480 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -846,11 +846,12 @@ fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) argv = g_new0 (gchar *, 2); /* local remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL || - fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); argv[0] = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + argv[0] = g_strdup (uri_tmp + 7); /* web remote, fu_util_install will download file */ } else { argv[0] = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); diff --git a/src/fu-util.c b/src/fu-util.c index a68bb408b..05236c267 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1973,13 +1973,16 @@ fu_util_update_device_with_release (FuUtilPrivate *priv, return FALSE; /* local and directory remotes have the firmware already */ - if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL || - fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); - /* install with flags chosen by the user */ fn = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + fn = g_strdup (uri_tmp + 7); + } + /* install with flags chosen by the user */ + if (fn != NULL) { return fwupd_client_install (priv->client, fwupd_device_get_id (dev), fn, priv->flags, NULL, error); From 1e35e4c22d97d445041b0e4807911c8d804f9313 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 28 Jan 2019 11:13:02 -0600 Subject: [PATCH 217/254] fu-tool: Port the `get-updates` command over Now that there is actually support to load non-static information (at least from fwupd perspective) it makes sense to support this command in both tools. --- data/bash-completion/fwupdtool.in | 1 + src/fu-tool.c | 50 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index bd0216916..198cd8f97 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -1,5 +1,6 @@ _fwupdtool_cmd_list=( 'build-firmware' + 'get-updates' 'get-details' 'get-devices' 'get-plugins' diff --git a/src/fu-tool.c b/src/fu-tool.c index 15c0ec480..3e5c77ccb 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -23,6 +23,7 @@ #include "fu-smbios.h" #include "fu-util-common.h" #include "fu-debug.h" +#include "fwupd-common-private.h" #define SYSTEMD_SERVICE "org.freedesktop.systemd1" #define SYSTEMD_OBJECT_PATH "/org/freedesktop/systemd1" @@ -386,6 +387,49 @@ fu_util_get_plugins (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, error)) + return FALSE; + + /* get devices from daemon */ + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return FALSE; + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GError) error_local = NULL; + + /* not going to have results, so save a D-Bus round-trip */ + if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) + continue; + + /* get the releases for this device and filter for validity */ + rels = fu_engine_get_upgrades (priv->engine, + fwupd_device_get_id (dev), + &error_local); + if (rels == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + g_print ("%s", fwupd_device_to_string (dev)); + g_print (" Release information:\n"); + /* print all releases */ + for (guint j = 0; j < rels->len; j++) { + FwupdRelease *rel = g_ptr_array_index (rels, j); + g_print ("%s\n", fwupd_release_to_string (rel)); + } + } + + /* success */ + return TRUE; +} + static gboolean fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1193,6 +1237,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Gets details about a firmware file"), fu_util_get_details); + fu_util_add (priv->cmd_array, + "get-updates", + NULL, + /* TRANSLATORS: command description */ + _("Gets the list of updates for connected hardware"), + fu_util_get_updates); fu_util_add (priv->cmd_array, "get-devices", NULL, From 32241f4256bfbc6d1042e7ae725edb7d7906dc59 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 24 Jan 2019 10:12:41 -0600 Subject: [PATCH 218/254] Add support for an `UpdateMessage` and display it in tools The idea is that if the user should know something about the device update "after" it's succesfully completed then the plugin can set `UpdateMessage` for the device and a client can show it. An example would be a device that doesn't reboot on its own and the user needs to power cycle it manually. --- libfwupd/fwupd-common.c | 4 +++ libfwupd/fwupd-device.c | 50 ++++++++++++++++++++++++++++++++++ libfwupd/fwupd-device.h | 3 ++ libfwupd/fwupd-enums-private.h | 1 + libfwupd/fwupd-release.c | 45 +++++++++++++++++++++++++++++- libfwupd/fwupd-release.h | 3 ++ libfwupd/fwupd.map | 4 +++ src/fu-engine.c | 10 +++++++ src/fu-tool.c | 22 +++++++++++++++ src/fu-util.c | 22 +++++++++++++++ 10 files changed, 163 insertions(+), 1 deletion(-) diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index 4578c3fe8..a32fbac90 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -380,6 +380,10 @@ fwupd_build_history_report_json_device (JsonBuilder *builder, FwupdDevice *dev) json_builder_set_member_name (builder, "UpdateError"); json_builder_add_string_value (builder, fwupd_device_get_update_error (dev)); } + if (fwupd_release_get_update_message (rel) != NULL) { + json_builder_set_member_name (builder, "UpdateMessage"); + json_builder_add_string_value (builder, fwupd_release_get_update_message (rel)); + } /* map back to the dev type on the LVFS */ json_builder_set_member_name (builder, "Guid"); diff --git a/libfwupd/fwupd-device.c b/libfwupd/fwupd-device.c index f8972d29e..324a77477 100644 --- a/libfwupd/fwupd-device.c +++ b/libfwupd/fwupd-device.c @@ -51,6 +51,7 @@ typedef struct { guint32 install_duration; FwupdUpdateState update_state; gchar *update_error; + gchar *update_message; GPtrArray *releases; FwupdDevice *parent; } FwupdDevicePrivate; @@ -977,6 +978,8 @@ fwupd_device_incorporate (FwupdDevice *self, FwupdDevice *donor) fwupd_device_set_plugin (self, priv_donor->plugin); if (priv->update_error == NULL) fwupd_device_set_update_error (self, priv_donor->update_error); + if (priv->update_message == NULL) + fwupd_device_set_update_message (self, priv_donor->update_message); if (priv->version == NULL) fwupd_device_set_version (self, priv_donor->version); if (priv->version_lowest == NULL) @@ -1133,6 +1136,11 @@ fwupd_device_to_variant_full (FwupdDevice *device, FwupdDeviceFlags flags) FWUPD_RESULT_KEY_UPDATE_ERROR, g_variant_new_string (priv->update_error)); } + if (priv->update_message != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_UPDATE_MESSAGE, + g_variant_new_string (priv->update_message)); + } if (priv->update_state != FWUPD_UPDATE_STATE_UNKNOWN) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_STATE, @@ -1287,6 +1295,10 @@ fwupd_device_from_key_value (FwupdDevice *device, const gchar *key, GVariant *va fwupd_device_set_update_error (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) { + fwupd_device_set_update_message (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_STATE) == 0) { fwupd_device_set_update_state (device, g_variant_get_uint32 (value)); return; @@ -1385,6 +1397,42 @@ fwupd_device_set_update_state (FwupdDevice *device, FwupdUpdateState update_stat priv->update_state = update_state; } +/** + * fwupd_device_get_update_message: + * @device: A #FwupdDevice + * + * Gets the update message. + * + * Returns: the update message, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_device_get_update_message (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->update_message; +} + +/** + * fwupd_device_set_update_message: + * @device: A #FwupdDevice + * @update_message: the update message string + * + * Sets the update message. + * + * Since: 1.2.4 + **/ +void +fwupd_device_set_update_message (FwupdDevice *device, const gchar *update_message) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_free (priv->update_message); + priv->update_message = g_strdup (update_message); +} + /** * fwupd_device_get_update_error: * @device: A #FwupdDevice @@ -1545,6 +1593,7 @@ fwupd_device_to_string (FwupdDevice *device) fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_MODIFIED, priv->modified); fwupd_pad_kv_ups (str, FWUPD_RESULT_KEY_UPDATE_STATE, priv->update_state); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); for (guint i = 0; i < priv->releases->len; i++) { FwupdRelease *release = g_ptr_array_index (priv->releases, i); g_autofree gchar *tmp = fwupd_release_to_string (release); @@ -1590,6 +1639,7 @@ fwupd_device_finalize (GObject *object) g_free (priv->vendor_id); g_free (priv->plugin); g_free (priv->update_error); + g_free (priv->update_message); g_free (priv->version); g_free (priv->version_lowest); g_free (priv->version_bootloader); diff --git a/libfwupd/fwupd-device.h b/libfwupd/fwupd-device.h index 8b79a8001..63061e999 100644 --- a/libfwupd/fwupd-device.h +++ b/libfwupd/fwupd-device.h @@ -112,6 +112,9 @@ void fwupd_device_set_update_state (FwupdDevice *device, const gchar *fwupd_device_get_update_error (FwupdDevice *device); void fwupd_device_set_update_error (FwupdDevice *device, const gchar *update_error); +const gchar *fwupd_device_get_update_message (FwupdDevice *device); +void fwupd_device_set_update_message (FwupdDevice *device, + const gchar *update_message); void fwupd_device_add_release (FwupdDevice *device, FwupdRelease *release); GPtrArray *fwupd_device_get_releases (FwupdDevice *device); diff --git a/libfwupd/fwupd-enums-private.h b/libfwupd/fwupd-enums-private.h index b61f7aad0..02b2d3d61 100644 --- a/libfwupd/fwupd-enums-private.h +++ b/libfwupd/fwupd-enums-private.h @@ -34,6 +34,7 @@ #define FWUPD_RESULT_KEY_SIZE "Size" /* t */ #define FWUPD_RESULT_KEY_SUMMARY "Summary" /* s */ #define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags" /* t */ +#define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_ERROR "UpdateError" /* s */ #define FWUPD_RESULT_KEY_UPDATE_STATE "UpdateState" /* u */ #define FWUPD_RESULT_KEY_URI "Uri" /* s */ diff --git a/libfwupd/fwupd-release.c b/libfwupd/fwupd-release.c index c36734c49..3a80ca475 100644 --- a/libfwupd/fwupd-release.c +++ b/libfwupd/fwupd-release.c @@ -48,6 +48,7 @@ typedef struct { guint64 size; guint32 install_duration; FwupdTrustFlags trust_flags; + gchar *update_message; } FwupdReleasePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FwupdRelease, fwupd_release, G_TYPE_OBJECT) @@ -161,6 +162,42 @@ fwupd_release_set_filename (FwupdRelease *release, const gchar *filename) priv->filename = g_strdup (filename); } +/** + * fwupd_release_get_update_message: + * @release: A #FwupdRelease + * + * Gets the update message. + * + * Returns: the update message, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_update_message (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->update_message; +} + +/** + * fwupd_release_set_update_message: + * @release: A #FwupdRelease + * @update_message: the update message string + * + * Sets the update message. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_update_message (FwupdRelease *release, const gchar *update_message) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->update_message); + priv->update_message = g_strdup (update_message); +} + /** * fwupd_release_get_protocol: * @release: A #FwupdRelease @@ -1019,6 +1056,10 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant fwupd_release_set_install_duration (release, g_variant_get_uint32 (value)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) { + fwupd_release_set_update_message (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { g_hash_table_unref (priv->metadata); priv->metadata = _variant_to_hash_kv (value); @@ -1121,7 +1162,8 @@ fwupd_release_to_string (FwupdRelease *release) fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR, priv->vendor); fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_TRUST_FLAGS, priv->trust_flags); fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); - + if (priv->update_message != NULL) + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); for (GList *l = keys; l != NULL; l = l->next) { @@ -1168,6 +1210,7 @@ fwupd_release_finalize (GObject *object) g_free (priv->vendor); g_free (priv->version); g_free (priv->remote_id); + g_free (priv->update_message); g_ptr_array_unref (priv->checksums); g_hash_table_unref (priv->metadata); diff --git a/libfwupd/fwupd-release.h b/libfwupd/fwupd-release.h index f698799b1..4b0d9493c 100644 --- a/libfwupd/fwupd-release.h +++ b/libfwupd/fwupd-release.h @@ -96,6 +96,9 @@ void fwupd_release_set_trust_flags (FwupdRelease *release, guint32 fwupd_release_get_install_duration (FwupdRelease *release); void fwupd_release_set_install_duration (FwupdRelease *release, guint32 duration); +const gchar *fwupd_release_get_update_message (FwupdRelease *release); +void fwupd_release_set_update_message (FwupdRelease *release, + const gchar *update_message); G_END_DECLS diff --git a/libfwupd/fwupd.map b/libfwupd/fwupd.map index ad053478e..41422a0a4 100644 --- a/libfwupd/fwupd.map +++ b/libfwupd/fwupd.map @@ -297,9 +297,13 @@ LIBFWUPD_1.2.2 { LIBFWUPD_1.2.4 { global: fwupd_client_get_tainted; + fwupd_device_get_update_message; + fwupd_device_set_update_message; fwupd_release_get_details_url; fwupd_release_get_source_url; + fwupd_release_get_update_message; fwupd_release_set_details_url; fwupd_release_set_source_url; + fwupd_release_set_update_message; local: *; } LIBFWUPD_1.2.2; diff --git a/src/fu-engine.c b/src/fu-engine.c index 79598461c..353c345cc 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -341,6 +341,9 @@ fu_engine_set_release_from_appstream (FuEngine *self, 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); } /* finds the remote-id for the first firmware in the silo that matches this @@ -2612,6 +2615,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self, } for (guint i = 0; i < releases_tmp->len; i++) { XbNode *release = g_ptr_array_index (releases_tmp, i); + const gchar *update_message; GPtrArray *checksums; g_autoptr(FwupdRelease) rel = fwupd_release_new (); @@ -2629,6 +2633,12 @@ fu_engine_add_releases_for_device_component (FuEngine *self, if (checksums->len == 0) continue; + /* add update message if exists but device doesn't already have one */ + update_message = fwupd_release_get_update_message (rel); + if (fwupd_device_get_update_message (FWUPD_DEVICE (device)) == NULL && + update_message != NULL) { + fwupd_device_set_update_message (FWUPD_DEVICE (device), update_message); + } /* success */ g_ptr_array_add (releases, g_steal_pointer (&rel)); } diff --git a/src/fu-tool.c b/src/fu-tool.c index 3e5c77ccb..cbb8dc1d8 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -53,6 +53,7 @@ typedef struct { /* only valid in update and downgrade */ FuUtilOperation current_operation; FwupdDevice *current_device; + gchar *current_message; FwupdDeviceFlags completion_flags; } FuUtilPrivate; @@ -300,6 +301,7 @@ fu_util_private_free (FuUtilPrivate *priv) g_object_unref (priv->progressbar); if (priv->context != NULL) g_option_context_free (priv->context); + g_free (priv->current_message); g_free (priv); } @@ -620,6 +622,21 @@ fu_util_update_device_changed_cb (FwupdClient *client, priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; else if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + + if (priv->current_message == NULL) { + const gchar *tmp = fwupd_device_get_update_message (priv->current_device); + if (tmp != NULL) + priv->current_message = g_strdup (tmp); + } +} + +static void +fu_util_display_current_message (FuUtilPrivate *priv) +{ + if (priv->current_message == NULL) + return; + g_print ("%s\n", priv->current_message); + g_clear_pointer (&priv->current_message, g_free); } static gboolean @@ -672,6 +689,8 @@ fu_util_install_blob (FuUtilPrivate *priv, gchar **values, GError **error) error)) return FALSE; + fu_util_display_current_message (priv); + /* success */ return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } @@ -827,6 +846,8 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) if (!fu_engine_install_tasks (priv->engine, install_tasks, blob_cab, priv->flags, error)) return FALSE; + fu_util_display_current_message (priv); + /* we don't want to ask anything */ if (priv->no_reboot_check) { g_debug ("skipping reboot check"); @@ -904,6 +925,7 @@ fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) g_printerr ("%s\n", error_local->message); continue; } + fu_util_display_current_message (priv); } } diff --git a/src/fu-util.c b/src/fu-util.c index 05236c267..9ac788bac 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -57,6 +57,7 @@ typedef struct { /* only valid in update and downgrade */ FuUtilOperation current_operation; FwupdDevice *current_device; + gchar *current_message; FwupdDeviceFlags completion_flags; } FuUtilPrivate; @@ -234,6 +235,11 @@ fu_util_update_device_changed_cb (FwupdClient *client, else if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + if (priv->current_message == NULL) { + const gchar *tmp = fwupd_device_get_update_message (priv->current_device); + if (tmp != NULL) + priv->current_message = g_strdup (tmp); + } } static FwupdDevice * @@ -648,6 +654,15 @@ fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GErro return g_steal_pointer (&filename); } +static void +fu_util_display_current_message (FuUtilPrivate *priv) +{ + if (priv->current_message == NULL) + return; + g_print ("%s\n", priv->current_message); + g_clear_pointer (&priv->current_message, g_free); +} + static gboolean fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -679,6 +694,8 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) if (!fwupd_client_install (priv->client, id, filename, priv->flags, NULL, error)) return FALSE; + fu_util_display_current_message (priv); + /* we don't want to ask anything */ if (priv->no_reboot_check) { g_debug ("skipping reboot check"); @@ -2046,6 +2063,8 @@ fu_util_update_all (FuUtilPrivate *priv, GError **error) rel = g_ptr_array_index (rels, 0); if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; + + fu_util_display_current_message (priv); } /* we don't want to ask anything */ @@ -2084,6 +2103,8 @@ fu_util_update_by_id (FuUtilPrivate *priv, const gchar *device_id, GError **erro if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; + fu_util_display_current_message (priv); + /* we don't want to ask anything */ if (priv->no_reboot_check) { g_debug ("skipping reboot check"); @@ -2209,6 +2230,7 @@ fu_util_private_free (FuUtilPrivate *priv) g_object_unref (priv->current_device); if (priv->soup_session != NULL) g_object_unref (priv->soup_session); + g_free (priv->current_message); g_main_loop_unref (priv->loop); g_object_unref (priv->cancellable); g_object_unref (priv->progressbar); From 5502cd5689a15d47ce5d7c0ea9617d791e770510 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 18 Jan 2019 15:13:23 -0600 Subject: [PATCH 219/254] dell-dock: Add support for a passive flow This behavior will prevent the dock from performing most resets until it has been unplugged from a host system. This significantly speeds up the perceived update duaration and prevents data loss during update. It's not confirmed whether EC23 or later EC will enable it. * So only enable by a custom flag until this is confirmed. * Custom flag will be dropped when included into stable EC release. This functionality also relies upon the CAB file providing a message warning user that the dock might not be usable after unplugging for up to 1 minute. --- plugins/dell-dock/README.md | 1 + plugins/dell-dock/fu-dell-dock-i2c-ec.c | 72 +++++++++++++++++++++--- plugins/dell-dock/fu-dell-dock-i2c-ec.h | 1 + plugins/dell-dock/fu-dell-dock-i2c-tbt.c | 4 +- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index 1800c1604..322067343 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -48,6 +48,7 @@ Custom flag use: This plugin uses the following plugin-specific custom flags: * `skip-restart`: Don't run the reset or reboot procedure of the component +* `try-passive-flow`: Tries to use the "EC passive flow" delaying updates Quirk use --------- diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index b4319cd2e..e51537d31 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -32,6 +32,7 @@ #define EC_CMD_MODIFY_LOCK 0x0a #define EC_CMD_RESET 0x0b #define EC_CMD_REBOOT 0x0c +#define EC_CMD_PASSIVE 0x0d #define EC_GET_FW_UPDATE_STATUS 0x0f #define EXPECTED_DOCK_INFO_SIZE 0xb7 @@ -42,6 +43,10 @@ #define BIT_SET(x,y) (x |= (1<passive_flow > 0) { + self->passive_flow |= PASSIVE_TBT_MASK; + return TRUE; + } + return FALSE; +} + static const gchar* fu_dell_dock_devicetype_to_str (guint device_type, guint sub_type) { @@ -408,6 +430,16 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, } fu_device_set_version_lowest (device, self->ec_minimum_version); + + /* TODO: Drop if minimum EC is set to 23+ + * Determine if the passive flow should be used when flashing + */ + if (fu_device_has_custom_flag (device, "try-passive-flow") && + fu_common_vercmp (self->ec_version, "00.00.00.23") >= 0) { + g_debug ("using passive flow"); + self->passive_flow = PASSIVE_REBOOT_MASK; + fu_device_set_custom_flags (device, "skip-restart"); + } return TRUE; } @@ -422,6 +454,7 @@ fu_dell_dock_ec_get_dock_data (FuDevice *device, const guint8 *result; gsize length = sizeof(FuDellDockDockDataStructure); g_autofree gchar *bundled_serial = NULL; + FuDellDockECFWUpdateStatus status; g_return_val_if_fail (device != NULL, FALSE); @@ -465,10 +498,20 @@ fu_dell_dock_ec_get_dock_data (FuDevice *device, /* copy this for being able to send in next commit transaction */ self->raw_versions->pkg_version = self->data->dock_firmware_pkg_ver; + /* read if passive update pending */ + if (!fu_dell_dock_get_ec_status (device, &status, error)) + return FALSE; + /* make sure this hardware spin matches our expecations */ if (self->data->board_id >= self->board_min) { - fu_dell_dock_ec_set_board (device); - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + if (status != FW_UPDATE_IN_PROGRESS) { + fu_dell_dock_ec_set_board (device); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_device_set_update_error (device, "An update is pending " + "next time the dock is " + "unplugged"); + } } else { g_warning ("This utility does not support this board, disabling updates for %s", fu_device_get_name (device)); @@ -560,18 +603,25 @@ fu_dell_dock_ec_reset (FuDevice *device, GError **error) gboolean fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) { - guint16 cmd = EC_CMD_REBOOT; + FuDellDockEc *self = FU_DELL_DOCK_EC (device); g_return_val_if_fail (device != NULL, FALSE); - if (fu_device_has_custom_flag (device, "skip-restart")) { - g_debug ("Skipping reboot per quirk request"); - return TRUE; + if (self->passive_flow > 0) { + guint32 cmd = EC_CMD_PASSIVE | /* cmd */ + 1 << 8 | /* length of data arguments */ + self->passive_flow << 16; + g_debug ("activating passive flow (%x) for %s", + self->passive_flow, + fu_device_get_name (device)); + return fu_dell_dock_ec_write (device, 3, (guint8 *) &cmd, error); + } else { + guint16 cmd = EC_CMD_REBOOT; + g_debug ("rebooting %s", fu_device_get_name (device)); + return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); } - g_debug ("Rebooting %s", fu_device_get_name (device)); - - return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); + return TRUE; } static gboolean @@ -726,6 +776,10 @@ fu_dell_dock_ec_write_fw (FuDevice *device, GBytes *blob_fw, /* dock will reboot to re-read; this is to appease the daemon */ fu_device_set_version (device, dynamic_version); + /* activate passive behavior */ + if (self->passive_flow) + self->passive_flow |= PASSIVE_RESET_MASK; + if (fu_device_has_custom_flag (device, "skip-restart")) { g_debug ("Skipping EC reset per quirk request"); return TRUE; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.h b/plugins/dell-dock/fu-dell-dock-i2c-ec.h index 123976946..db597c3ff 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.h +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.h @@ -32,6 +32,7 @@ FuDellDockEc *fu_dell_dock_ec_new (FuDevice *symbiote); G_END_DECLS gboolean fu_dell_dock_ec_needs_tbt (FuDevice *device); +gboolean fu_dell_dock_ec_tbt_passive (FuDevice *device); gboolean fu_dell_dock_ec_modify_lock (FuDevice *self, guint8 target, gboolean unlocked, diff --git a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c index e8696275c..5d5b909c5 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c @@ -118,8 +118,8 @@ fu_dell_dock_tbt_write_fw (FuDevice *device, fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); - if (fu_device_has_custom_flag (device, "skip-restart")) { - g_debug ("skipping TBT reset per quirk request"); + if (fu_dell_dock_ec_tbt_passive (fu_device_get_parent (device))) { + g_debug ("using passive flow for Thunderbolt"); } else if (!fu_dell_dock_hid_tbt_authenticate (self->symbiote, &tbt_base_settings, error)) { From fc4fbfc98fe6c0b40c0b8cff93c2f874540ce1d4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 15:23:20 +0000 Subject: [PATCH 220/254] udev-device: Fix critical warning if the device has no parent --- src/fu-udev-device.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index db726bb7d..6c1d5d658 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -91,6 +91,7 @@ fu_udev_device_probe (FuDevice *device, GError **error) FuUdevDevicePrivate *priv = GET_PRIVATE (self); const gchar *tmp; g_autofree gchar *subsystem = NULL; + g_autoptr(GUdevDevice) udev_parent = NULL; /* set ven:dev:rev */ priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "vendor"); @@ -98,17 +99,18 @@ fu_udev_device_probe (FuDevice *device, GError **error) priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "revision"); /* fallback to the parent */ - if (priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0) { - g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (priv->udev_device); - priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (parent, "vendor"); - priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (parent, "device"); - priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (parent, "revision"); + udev_parent = g_udev_device_get_parent (priv->udev_device); + if (udev_parent != NULL && + priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0) { + priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "vendor"); + priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "device"); + priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "revision"); } /* hidraw helpfully encodes the information in a different place */ - if (priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0 && + if (udev_parent != NULL && + priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0 && g_strcmp0 (g_udev_device_get_subsystem (priv->udev_device), "hidraw") == 0) { - g_autoptr(GUdevDevice) udev_parent = g_udev_device_get_parent (priv->udev_device); tmp = g_udev_device_get_property (udev_parent, "HID_ID"); if (tmp != NULL && strlen (tmp) == 22) { priv->vendor = fu_udev_device_read_uint16 (tmp + 10); From caadb7b66aa501b06485bbd46c04fffa1d1c89eb Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 15:23:51 +0000 Subject: [PATCH 221/254] udev-device: Fall back to non-database model and vendor values --- src/fu-udev-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index 6c1d5d658..263485d4a 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -141,6 +141,8 @@ fu_udev_device_probe (FuDevice *device, GError **error) tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_MODEL"); if (tmp == NULL) tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL_FROM_DATABASE"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL"); if (tmp != NULL) fu_device_set_name (device, tmp); } @@ -150,6 +152,8 @@ fu_udev_device_probe (FuDevice *device, GError **error) tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_VENDOR"); if (tmp == NULL) tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR_FROM_DATABASE"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR"); if (tmp != NULL) fu_device_set_vendor (device, tmp); } From 297e1e89710eb8bbcd07503ca05a8fbc739df681 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 15:24:14 +0000 Subject: [PATCH 222/254] udev-device: Set the serial number automatically --- src/fu-udev-device.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index 263485d4a..49e129316 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -158,6 +158,15 @@ fu_udev_device_probe (FuDevice *device, GError **error) fu_device_set_vendor (device, tmp); } + /* set serial */ + if (fu_device_get_serial (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL_SHORT"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL"); + if (tmp != NULL) + fu_device_set_serial (device, tmp); + } + /* set vendor ID */ subsystem = g_ascii_strup (fu_udev_device_get_subsystem (self), -1); if (subsystem != NULL && priv->vendor != 0x0000) { From 57d8afd659fe7e4e47880331afb12377658148ed Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 15:24:29 +0000 Subject: [PATCH 223/254] udev-device: Set the firmware revision automatically --- src/fu-udev-device.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index 49e129316..40321893c 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -167,6 +167,13 @@ fu_udev_device_probe (FuDevice *device, GError **error) fu_device_set_serial (device, tmp); } + /* set revision */ + if (fu_device_get_version (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "ID_REVISION"); + if (tmp != NULL) + fu_device_set_version (device, tmp); + } + /* set vendor ID */ subsystem = g_ascii_strup (fu_udev_device_get_subsystem (self), -1); if (subsystem != NULL && priv->vendor != 0x0000) { From 82f7499faa530eb79f70af45b0bc93e9e24bec3d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 15:25:17 +0000 Subject: [PATCH 224/254] udev-device: Add a utility function for debugging I normally have to remember this trick every time I write a new plugin, so include this in the common code to be called by plugins as required. --- src/fu-udev-device.c | 28 +++++++++++++++++++++++++++- src/fu-udev-device.h | 3 ++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index 40321893c..c888ebdc3 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -83,6 +83,32 @@ fu_udev_device_read_uint16 (const gchar *str) return (guint16) g_ascii_strtoull (buf, NULL, 16); } +static void +fu_udev_device_dump_internal (GUdevDevice *udev_device) +{ +#ifdef HAVE_GUDEV_232 + const gchar * const *keys; + + keys = g_udev_device_get_property_keys (udev_device); + for (guint i = 0; keys[i] != NULL; i++) { + g_debug ("%s={%s}", keys[i], + g_udev_device_get_property (udev_device, keys[i])); + } + keys = g_udev_device_get_sysfs_attr_keys (udev_device); + for (guint i = 0; keys[i] != NULL; i++) { + g_debug ("%s=[%s]", keys[i], + g_udev_device_get_sysfs_attr (udev_device, keys[i])); + } +#endif +} + +void +fu_udev_device_dump (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + fu_udev_device_dump_internal (priv->udev_device); +} + static gboolean fu_udev_device_probe (FuDevice *device, GError **error) { diff --git a/src/fu-udev-device.h b/src/fu-udev-device.h index ca72f3309..be8e1e03c 100644 --- a/src/fu-udev-device.h +++ b/src/fu-udev-device.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Richard Hughes + * Copyright (C) 2017-2019 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -35,6 +35,7 @@ guint8 fu_udev_device_get_revision (FuUdevDevice *self); gboolean fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystem, GError **error); +void fu_udev_device_dump (FuUdevDevice *self); G_END_DECLS From a08891b6cb74ae35424e07f188e7e8333a14dab4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Jan 2019 20:38:57 +0000 Subject: [PATCH 225/254] trivial: Do not use the testing remote for the Fedora CI --- contrib/ci/Dockerfile-fedora.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ci/Dockerfile-fedora.in b/contrib/ci/Dockerfile-fedora.in index 9bd2d58f0..6f6994316 100644 --- a/contrib/ci/Dockerfile-fedora.in +++ b/contrib/ci/Dockerfile-fedora.in @@ -4,7 +4,7 @@ ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id -RUN dnf --enablerepo=updates-testing -y update +RUN dnf -y update RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN mkdir /build From f6838c738aa178e026ee543abca6e36a8fa2fbec Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Jan 2019 10:54:18 +0000 Subject: [PATCH 226/254] trivial: Add fu_udev_device_get_slot_depth() We'll need this for another plugin soon. --- plugins/nvme/fu-nvme-device.c | 20 +------------------- src/fu-udev-device.c | 18 ++++++++++++++++++ src/fu-udev-device.h | 2 ++ 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/plugins/nvme/fu-nvme-device.c b/plugins/nvme/fu-nvme-device.c index 1470f5a1d..d39609b14 100644 --- a/plugins/nvme/fu-nvme-device.c +++ b/plugins/nvme/fu-nvme-device.c @@ -305,24 +305,6 @@ fu_nvme_device_parse_cns (FuNvmeDevice *self, const guint8 *buf, gsize sz, GErro return TRUE; } -static guint -fu_nvme_device_pci_slot_depth (FuNvmeDevice *self) -{ - GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (self)); - g_autoptr(GUdevDevice) device_tmp = NULL; - - device_tmp = g_udev_device_get_parent_with_subsystem (udev_device, "pci", NULL); - if (device_tmp == NULL) - return 0; - for (guint i = 0; i < 0xff; i++) { - g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (device_tmp); - if (parent == NULL) - return i; - g_set_object (&device_tmp, parent); - } - return 0; -} - static void fu_nvme_device_dump (const gchar *title, const guint8 *buf, gsize sz) { @@ -369,7 +351,7 @@ fu_nvme_device_probe (FuUdevDevice *device, GError **error) return FALSE; /* look at the PCI depth to work out if in an external enclosure */ - self->pci_depth = fu_nvme_device_pci_slot_depth (self); + self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); if (self->pci_depth <= 2) fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index c888ebdc3..e9229c641 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -251,6 +251,24 @@ fu_udev_device_set_dev (FuUdevDevice *self, GUdevDevice *udev_device) return; } +guint +fu_udev_device_get_slot_depth (FuUdevDevice *self, const gchar *subsystem) +{ + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (self)); + g_autoptr(GUdevDevice) device_tmp = NULL; + + device_tmp = g_udev_device_get_parent_with_subsystem (udev_device, subsystem, NULL); + if (device_tmp == NULL) + return 0; + for (guint i = 0; i < 0xff; i++) { + g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (device_tmp); + if (parent == NULL) + return i; + g_set_object (&device_tmp, parent); + } + return 0; +} + static void fu_udev_device_incorporate (FuDevice *self, FuDevice *donor) { diff --git a/src/fu-udev-device.h b/src/fu-udev-device.h index be8e1e03c..efb76b9f9 100644 --- a/src/fu-udev-device.h +++ b/src/fu-udev-device.h @@ -32,6 +32,8 @@ const gchar *fu_udev_device_get_subsystem (FuUdevDevice *self); guint16 fu_udev_device_get_vendor (FuUdevDevice *self); guint16 fu_udev_device_get_model (FuUdevDevice *self); guint8 fu_udev_device_get_revision (FuUdevDevice *self); +guint fu_udev_device_get_slot_depth (FuUdevDevice *self, + const gchar *subsystem); gboolean fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystem, GError **error); From bdd17b6ffcd8feba4f91a175f0d9fe8a88f35769 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Jan 2019 10:55:08 +0000 Subject: [PATCH 227/254] trivial: Use DEVPATH for the physical ID when using scsi devices --- src/fu-udev-device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index e9229c641..7d55a8a1d 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -436,7 +436,8 @@ fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystem, GErr return FALSE; } physical_id = g_strdup_printf ("PCI_SLOT_NAME=%s", tmp); - } else if (g_strcmp0 (subsystem, "usb") == 0) { + } else if (g_strcmp0 (subsystem, "usb") == 0 || + g_strcmp0 (subsystem, "scsi") == 0) { tmp = g_udev_device_get_property (udev_device, "DEVPATH"); if (tmp == NULL) { g_set_error_literal (error, From 62eae7a9812373bf74fc6c1dc82479999cd29465 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Jan 2019 10:55:53 +0000 Subject: [PATCH 228/254] trivial: Show the possible subsystems when failing to set the physical ID This makes new plugin development much easier. --- src/fu-udev-device.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/fu-udev-device.c b/src/fu-udev-device.c index 7d55a8a1d..5c7e4db80 100644 --- a/src/fu-udev-device.c +++ b/src/fu-udev-device.c @@ -386,6 +386,29 @@ fu_udev_device_get_revision (FuUdevDevice *self) return priv->revision; } +static GString * +fu_udev_device_get_parent_subsystems (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + GString *str = g_string_new (NULL); + g_autoptr(GUdevDevice) udev_device = g_object_ref (priv->udev_device); + + /* find subsystems of all parent devices */ + while (TRUE) { + g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (udev_device); + if (parent == NULL) + break; + if (g_udev_device_get_subsystem (parent) != NULL) { + g_string_append_printf (str, "%s,", + g_udev_device_get_subsystem (parent)); + } + g_set_object (&udev_device, g_steal_pointer (&parent)); + } + if (str->len > 0) + g_string_truncate (str, str->len - 1); + return str; +} + /** * fu_udev_device_set_physical_id: * @self: A #GUdevDevice @@ -418,11 +441,13 @@ fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystem, GErr udev_device = g_udev_device_get_parent_with_subsystem (priv->udev_device, subsystem, NULL); if (udev_device == NULL) { + g_autoptr(GString) str = NULL; + str = fu_udev_device_get_parent_subsystems (self); g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "failed to find device with subsystem %s", - subsystem); + "failed to find device with subsystem %s, only got %s", + subsystem, str->str); return FALSE; } } From 4fef28d0ac7266f2b12f45eb998754f277e1117f Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Jan 2019 19:54:48 +0000 Subject: [PATCH 229/254] trivial: Add the missing protocol IDs to the plugin READMEs --- plugins/altos/README.md | 4 ++++ plugins/colorhug/README.md | 4 ++++ plugins/csr/README.md | 4 ++++ plugins/dell-dock/README.md | 5 +++++ plugins/dfu/README.md | 5 +++++ plugins/ebitdo/README.md | 4 ++++ plugins/fastboot/README.md | 4 ++++ plugins/flashrom/README.md | 4 ++++ plugins/nvme/README.md | 4 ++++ plugins/redfish/README.md | 4 ++++ plugins/rts54hid/README.md | 4 ++++ plugins/rts54hub/README.md | 4 ++++ plugins/synapticsmst/README.md | 4 ++++ plugins/thunderbolt/README.md | 4 ++++ plugins/uefi/README.md | 4 ++++ plugins/unifying/README.md | 5 +++++ plugins/wacom-raw/README.md | 10 ++++++++++ plugins/wacom-raw/fu-plugin-wacom-raw.c | 1 + plugins/wacom-usb/README.md | 4 ++++ 19 files changed, 82 insertions(+) diff --git a/plugins/altos/README.md b/plugins/altos/README.md index 8d0eeabb9..bc21b2860 100644 --- a/plugins/altos/README.md +++ b/plugins/altos/README.md @@ -21,6 +21,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in ELF file format. The firmware image is inserted into the `.text` section. +This plugin supports the following protocol ID: + + * org.altusmetrum.altos + GUID Generation --------------- diff --git a/plugins/colorhug/README.md b/plugins/colorhug/README.md index 38747241d..4055adcab 100644 --- a/plugins/colorhug/README.md +++ b/plugins/colorhug/README.md @@ -17,6 +17,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in a packed binary file format. +This plugin supports the following protocol ID: + + * com.hughski.colorhug + GUID Generation --------------- diff --git a/plugins/csr/README.md b/plugins/csr/README.md index 645da33b6..2780fe248 100644 --- a/plugins/csr/README.md +++ b/plugins/csr/README.md @@ -22,6 +22,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in DFU file format. +This plugin supports the following protocol ID: + + * com.qualcomm.dfu + GUID Generation --------------- diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index 322067343..00ecbee32 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -31,6 +31,11 @@ Firmware Format The daemon will decompress the cabinet archive and extract several firmware blobs with an unspecified binary file format. +This plugin supports the following protocol ID: + + * com.dell.dock + * com.synaptics.mst + GUID Generation --------------- diff --git a/plugins/dfu/README.md b/plugins/dfu/README.md index 6dcc0a79b..f251486ae 100644 --- a/plugins/dfu/README.md +++ b/plugins/dfu/README.md @@ -13,6 +13,11 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in DFU or DfuSe file format. +This plugin supports the following protocol IDs: + + * org.usb.dfu + * com.st.dfuse + GUID Generation --------------- diff --git a/plugins/ebitdo/README.md b/plugins/ebitdo/README.md index 3e16f76a8..ec7a518fb 100644 --- a/plugins/ebitdo/README.md +++ b/plugins/ebitdo/README.md @@ -19,6 +19,10 @@ The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format. The binary file has a vendor-specific header that is used when flashing the image. +This plugin supports the following protocol ID: + + * com.8bitdo + GUID Generation --------------- diff --git a/plugins/fastboot/README.md b/plugins/fastboot/README.md index 328cedfb5..43eeb3b9e 100644 --- a/plugins/fastboot/README.md +++ b/plugins/fastboot/README.md @@ -18,6 +18,10 @@ the manifest must be either an Android `flashfile.xml` format file, or a QFIL For both types, all partitions with a defined image found in the zip file will be updated. +This plugin supports the following protocol ID: + + * com.google.fastboot + GUID Generation --------------- diff --git a/plugins/flashrom/README.md b/plugins/flashrom/README.md index cce935dce..bc19ca43f 100644 --- a/plugins/flashrom/README.md +++ b/plugins/flashrom/README.md @@ -13,6 +13,10 @@ The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format, which is typically the raw input for an EEPROM programmer. +This plugin supports the following protocol ID: + + * org.flashrom + GUID Generation --------------- diff --git a/plugins/nvme/README.md b/plugins/nvme/README.md index 8b6bb2f3f..0be4da61a 100644 --- a/plugins/nvme/README.md +++ b/plugins/nvme/README.md @@ -17,6 +17,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format. +This plugin supports the following protocol ID: + + * org.nvmexpress + GUID Generation --------------- diff --git a/plugins/redfish/README.md b/plugins/redfish/README.md index df3d1683b..7157dd17a 100644 --- a/plugins/redfish/README.md +++ b/plugins/redfish/README.md @@ -16,6 +16,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format. +This plugin supports the following protocol ID: + + * org.dmtf.redfish + GUID Generation --------------- diff --git a/plugins/rts54hid/README.md b/plugins/rts54hid/README.md index dd9e3f967..1670bc323 100644 --- a/plugins/rts54hid/README.md +++ b/plugins/rts54hid/README.md @@ -16,6 +16,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format. +This plugin supports the following protocol ID: + + * com.realtek.rts54 + GUID Generation --------------- diff --git a/plugins/rts54hub/README.md b/plugins/rts54hub/README.md index 2f91ac98b..a59fe86d8 100644 --- a/plugins/rts54hub/README.md +++ b/plugins/rts54hub/README.md @@ -16,6 +16,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format. +This plugin supports the following protocol ID: + + * com.realtek.rts54 + GUID Generation --------------- diff --git a/plugins/synapticsmst/README.md b/plugins/synapticsmst/README.md index 5b1e3ea0a..1428db78f 100644 --- a/plugins/synapticsmst/README.md +++ b/plugins/synapticsmst/README.md @@ -9,6 +9,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format. +This plugin supports the following protocol ID: + + * com.synaptics.mst + GUID Generation --------------- diff --git a/plugins/thunderbolt/README.md b/plugins/thunderbolt/README.md index 9d48a12b5..8b235593c 100644 --- a/plugins/thunderbolt/README.md +++ b/plugins/thunderbolt/README.md @@ -15,6 +15,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in an unspecified binary file format, with vendor specific header. +This plugin supports the following protocol ID: + + * com.intel.thunderbolt + GUID Generation --------------- diff --git a/plugins/uefi/README.md b/plugins/uefi/README.md index ce0713791..7f05c0afd 100644 --- a/plugins/uefi/README.md +++ b/plugins/uefi/README.md @@ -20,6 +20,10 @@ EFI capsule file format. See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf for details. +This plugin supports the following protocol ID: + + * org.uefi.capsule + GUID Generation --------------- diff --git a/plugins/unifying/README.md b/plugins/unifying/README.md index 8f9497a99..c4e913a30 100644 --- a/plugins/unifying/README.md +++ b/plugins/unifying/README.md @@ -22,6 +22,11 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in a vendor-specific format that appears to be a subset of the Intel HEX format. +This plugin supports the following protocol IDs: + + * com.logitech.unifying + * com.logitech.unifyingsigned + GUID Generation --------------- diff --git a/plugins/wacom-raw/README.md b/plugins/wacom-raw/README.md index 878b99542..2d5f3890a 100644 --- a/plugins/wacom-raw/README.md +++ b/plugins/wacom-raw/README.md @@ -15,6 +15,16 @@ The HID DeviceInstanceId values are used, e.g. `HIDRAW\VEN_056A&DEV_4875`. Additionally, for supported AES devices an extra GUID is added for the hardware ID (e.g. `WACOM\HWID_%04X`) to further disambiguate the panels. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +Intel HEX file format. + +This plugin supports the following protocol ID: + + * com.wacom.raw + Quirk use --------- This plugin uses the following plugin-specific quirks: diff --git a/plugins/wacom-raw/fu-plugin-wacom-raw.c b/plugins/wacom-raw/fu-plugin-wacom-raw.c index 75c928462..d1e72456d 100644 --- a/plugins/wacom-raw/fu-plugin-wacom-raw.c +++ b/plugins/wacom-raw/fu-plugin-wacom-raw.c @@ -15,6 +15,7 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.wacom.raw"); fu_plugin_add_udev_subsystem (plugin, "hidraw"); } diff --git a/plugins/wacom-usb/README.md b/plugins/wacom-usb/README.md index d40e319a4..83fad5d53 100644 --- a/plugins/wacom-usb/README.md +++ b/plugins/wacom-usb/README.md @@ -22,6 +22,10 @@ Firmware Format The daemon will decompress the cabinet archive and extract a firmware blob in SREC file format, with a custom vendor header. +This plugin supports the following protocol ID: + + * com.wacom.usb + GUID Generation --------------- From 0bf8ee810b8b9896f971ddbb35b1e366ee45f269 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 28 Jan 2019 15:31:45 +0000 Subject: [PATCH 230/254] ata: Add a new plugin to upgrade firmware on ATA/ATAPI hardware Some of the ATA12 fixup code is by Mark Lord, taken from the hdparm project. Fixes: https://github.com/hughsie/fwupd/issues/946 --- contrib/fwupd.spec.in | 1 + plugins/ata/README.md | 44 ++ plugins/ata/ata.quirk | 1 + plugins/ata/fu-ata-device.c | 617 +++++++++++++++++++++++ plugins/ata/fu-ata-device.h | 28 + plugins/ata/fu-plugin-ata.c | 60 +++ plugins/ata/fu-self-test.c | 50 ++ plugins/ata/meson.build | 58 +++ plugins/ata/tests/StarDrive-SBFM61.2.bin | Bin 0 -> 512 bytes plugins/meson.build | 1 + 10 files changed, 860 insertions(+) create mode 100644 plugins/ata/README.md create mode 100644 plugins/ata/ata.quirk create mode 100644 plugins/ata/fu-ata-device.c create mode 100644 plugins/ata/fu-ata-device.h create mode 100644 plugins/ata/fu-plugin-ata.c create mode 100644 plugins/ata/fu-self-test.c create mode 100644 plugins/ata/meson.build create mode 100644 plugins/ata/tests/StarDrive-SBFM61.2.bin diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index b2354b5d6..e17976c4e 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -258,6 +258,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %dir %{_libdir}/fwupd-plugins-3 %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so %{_libdir}/fwupd-plugins-3/libfu_plugin_colorhug.so %{_libdir}/fwupd-plugins-3/libfu_plugin_csr.so %if 0%{?have_dell} diff --git a/plugins/ata/README.md b/plugins/ata/README.md new file mode 100644 index 000000000..decbfe28c --- /dev/null +++ b/plugins/ata/README.md @@ -0,0 +1,44 @@ +ATA +=== + +Introduction +------------ + +This plugin allows updating ATA/ATAPI storage hardware. Devices are enumerated +from the block devices and if ID_ATA_DOWNLOAD_MICROCODE is supported they can +be updated with appropriate firmware file. + +Updating ATA devices is more dangerous than other hardware such as DFU or NVMe +and should be tested carefully with the help of the drive vendor. + +The device GUID is read from the trimmed model string. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * org.t13.ata + +GUID Generation +--------------- + +These device use the Microsoft DeviceInstanceId values, e.g. + + * `IDE\VENDOR[40]REVISION[8]` + * `IDE\0VENDOR[40]` + +See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices +for more details. + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|-------------------------------------------|-----------------------| +| `AtaTransferBlocks` | Blocks to transfer, or `0xffff` for max | 1.2.4 | +| `AtaTransferMode` | The transfer mode, `0x3`, `0x7` or `0xe` | 1.2.4 | diff --git a/plugins/ata/ata.quirk b/plugins/ata/ata.quirk new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/plugins/ata/ata.quirk @@ -0,0 +1 @@ + diff --git a/plugins/ata/fu-ata-device.c b/plugins/ata/fu-ata-device.c new file mode 100644 index 000000000..c91bf514e --- /dev/null +++ b/plugins/ata/fu-ata-device.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-ata-device.h" +#include "fu-chunk.h" + +#define FU_ATA_IDENTIFY_SIZE 512 /* bytes */ +#define FU_ATA_BLOCK_SIZE 512 /* bytes */ + +struct ata_tf { + guint8 dev; + guint8 command; + guint8 error; + guint8 status; + guint8 feat; + guint8 nsect; + guint8 lbal; + guint8 lbam; + guint8 lbah; +}; + +#define ATA_USING_LBA (1 << 6) +#define ATA_STAT_DRQ (1 << 3) +#define ATA_STAT_ERR (1 << 0) + +#define ATA_OP_IDENTIFY 0xec +#define ATA_OP_DOWNLOAD_MICROCODE 0x92 + +#define SG_CHECK_CONDITION 0x02 +#define SG_DRIVER_SENSE 0x08 + +#define SG_ATA_12 0xa1 +#define SG_ATA_12_LEN 12 + +#define SG_ATA_PROTO_NON_DATA (3 << 1) +#define SG_ATA_PROTO_PIO_IN (4 << 1) +#define SG_ATA_PROTO_PIO_OUT (5 << 1) + +enum { + SG_CDB2_TLEN_NODATA = 0 << 0, + SG_CDB2_TLEN_FEAT = 1 << 0, + SG_CDB2_TLEN_NSECT = 2 << 0, + + SG_CDB2_TLEN_BYTES = 0 << 2, + SG_CDB2_TLEN_SECTORS = 1 << 2, + + SG_CDB2_TDIR_TO_DEV = 0 << 3, + SG_CDB2_TDIR_FROM_DEV = 1 << 3, + + SG_CDB2_CHECK_COND = 1 << 5, +}; + +struct _FuAtaDevice { + FuUdevDevice parent_instance; + guint pci_depth; + gint fd; + guint16 transfer_blocks; + guint8 transfer_mode; +}; + +G_DEFINE_TYPE (FuAtaDevice, fu_ata_device, FU_TYPE_UDEV_DEVICE) + +#ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop +#endif + +guint8 +fu_ata_device_get_transfer_mode (FuAtaDevice *self) +{ + return self->transfer_mode; +} + +guint16 +fu_ata_device_get_transfer_blocks (FuAtaDevice *self) +{ + return self->transfer_blocks; +} + +static gchar * +fu_ata_device_get_string (const guint16 *buf, guint start, guint end) +{ + g_autoptr(GString) str = g_string_new (NULL); + for (guint i = start; i <= end; i++) { + g_string_append_c (str, (gchar) (buf[i] >> 8)); + g_string_append_c (str, (gchar) (buf[i] & 0xff)); + } + + /* remove whitespace before returning */ + if (str->len > 0) { + g_strchomp (str->str); + if (str->str[0] == '\0') + return NULL; + } + return g_string_free (g_steal_pointer (&str), FALSE); +} + +static void +fu_ata_device_to_string (FuDevice *device, GString *str) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + g_string_append (str, " FuAtaDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", self->fd); + g_string_append_printf (str, " transfer-mode:\t0x%x\n", (guint) self->transfer_mode); + g_string_append_printf (str, " transfer-size:\t0x%x\n", (guint) self->transfer_blocks); + g_string_append_printf (str, " pci-depth:\t\t%u\n", self->pci_depth); +} + +/* https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices */ +static gchar * +fu_ata_device_pad_string_for_id (const gchar *name) +{ + GString *str = g_string_new (name); + fu_common_string_replace (str, " ", "_"); + for (guint i = str->len; i < 40; i++) + g_string_append_c (str, '_'); + return g_string_free (str, FALSE); +} + +static gboolean +fu_ata_device_parse_id (FuAtaDevice *self, const guint8 *buf, gsize sz, GError **error) +{ + FuDevice *device = FU_DEVICE (self); + guint16 xfer_min = 1; + guint16 xfer_max = 0xffff; + guint16 id[FU_ATA_IDENTIFY_SIZE/2]; + g_autofree gchar *name_pad = NULL; + g_autofree gchar *sku = NULL; + + /* check size */ + if (sz != FU_ATA_IDENTIFY_SIZE) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "ID incorrect size, got 0x%02x", + (guint) sz); + return FALSE; + } + + /* read LE buffer */ + for (guint i = 0; i < sz / 2; i++) + id[i] = fu_common_read_uint16 (buf + (i * 2), G_LITTLE_ENDIAN); + + /* verify drive correctly supports DOWNLOAD_MICROCODE */ + if (!(id[83] & 1 && id[86] & 1)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "DOWNLOAD_MICROCODE not supported by device"); + return FALSE; + } + + /* fallback to a sane default */ + if (self->transfer_mode == 0x0) { + if ((id[119] & 0x10) && (id[120] & 0x10)) + self->transfer_mode = 0x3; + else + self->transfer_mode = 0x7; + } + + /* the newer, segmented transfer mode */ + if (self->transfer_mode == 0x3 || self->transfer_mode == 0xe) { + xfer_min = id[234]; + if (xfer_min == 0x0 || xfer_min == 0xffff) + xfer_min = 1; + xfer_max = id[235]; + if (xfer_max == 0x0 || xfer_max == 0xffff) + xfer_max = xfer_min; + } + + /* fall back to a sane block size */ + if (self->transfer_blocks == 0x0) + self->transfer_blocks = xfer_min; + else if (self->transfer_blocks == 0xffff) + self->transfer_blocks = xfer_max; + + /* get values in case the kernel didn't */ + if (fu_device_get_serial (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 10, 19); + fu_device_set_serial (device, tmp); + } + if (fu_device_get_name (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 27, 46); + fu_device_set_name (device, tmp); + } + if (fu_device_get_version (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 23, 26); + fu_device_set_version (device, tmp); + } + + /* 8 byte additional product identifier == SKU? */ + sku = fu_ata_device_get_string (id, 170, 173); + if (sku != NULL) + g_debug ("SKU=%s", sku); + + /* add extra GUIDs */ + name_pad = fu_ata_device_pad_string_for_id (fu_device_get_name (device)); + if (name_pad != NULL && + fu_device_get_version (device) != NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("IDE\\%s%s", name_pad, + fu_device_get_version (device)); + fu_device_add_guid (device, tmp); + } + if (name_pad != NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("IDE\\0%s", name_pad); + fu_device_add_guid (device, tmp); + } + + return TRUE; +} + +static gboolean +fu_ata_device_open (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* open device */ + self->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDONLY); + if (self->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s: %s", + g_udev_device_get_device_file (udev_device), + strerror (errno)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_probe (FuUdevDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "scsi", error)) + return FALSE; + + /* look at the PCI depth to work out if in an external enclosure */ + self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); + if (self->pci_depth <= 2) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + + return TRUE; +} + +static guint64 +fu_ata_device_tf_to_pack_id (struct ata_tf *tf) +{ + guint32 lba24 = (tf->lbah << 16) | (tf->lbam << 8) | (tf->lbal); + guint32 lbah = tf->dev & 0x0f; + return (((guint64) lbah) << 24) | (guint64) lba24; +} + +static gboolean +fu_ata_device_command (FuAtaDevice *self, struct ata_tf *tf, + gint dxfer_direction, guint timeout_ms, + guint8 *dxferp, gsize dxfer_len, GError **error) +{ + guint8 cdb[SG_ATA_12_LEN] = { 0x0 }; + guint8 sb[32] = { 0x0 }; + sg_io_hdr_t io_hdr = { 0x0 }; + + /* map _TO_DEV to PIO mode */ + if (dxfer_direction == SG_DXFER_TO_DEV) + cdb[1] = SG_ATA_PROTO_PIO_OUT; + else if (dxfer_direction == SG_DXFER_FROM_DEV) + cdb[1] = SG_ATA_PROTO_PIO_IN; + else + cdb[1] = SG_ATA_PROTO_NON_DATA; + + /* libata workaround: don't demand sense data for IDENTIFY */ + if (dxfer_len > 0) { + cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS; + cdb[2] |= dxfer_direction == SG_DXFER_TO_DEV ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV; + } else { + cdb[2] = SG_CDB2_CHECK_COND; + } + + /* populate non-LBA48 CDB */ + cdb[0] = SG_ATA_12; + cdb[3] = tf->feat; + cdb[4] = tf->nsect; + cdb[5] = tf->lbal; + cdb[6] = tf->lbam; + cdb[7] = tf->lbah; + cdb[8] = tf->dev; + cdb[9] = tf->command; + fu_common_dump_raw (G_LOG_DOMAIN, "CBD", cdb, sizeof(cdb)); + if (dxfer_direction == SG_DXFER_TO_DEV && dxferp != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "outgoing_data", + dxferp, dxfer_len); + } + + /* hit hardware */ + io_hdr.interface_id = 'S'; + io_hdr.mx_sb_len = sizeof(sb); + io_hdr.dxfer_direction = dxfer_direction; + io_hdr.dxfer_len = dxfer_len; + io_hdr.dxferp = dxferp; + io_hdr.cmdp = cdb; + io_hdr.cmd_len = SG_ATA_12_LEN; + io_hdr.sbp = sb; + io_hdr.pack_id = fu_ata_device_tf_to_pack_id (tf); + io_hdr.timeout = timeout_ms; + if (ioctl (self->fd, SG_IO, &io_hdr) == -1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "SG_IO not supported: %s", + strerror (errno)); + return FALSE; + } + g_debug ("ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x", + io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); + fu_common_dump_raw (G_LOG_DOMAIN, "SB", sb, sizeof(sb)); + + /* error check */ + if (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad status: 0x%x", io_hdr.status); + return FALSE; + } + if (io_hdr.host_status) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad host status: 0x%x", io_hdr.host_status); + return FALSE; + } + if (io_hdr.driver_status && (io_hdr.driver_status != SG_DRIVER_SENSE)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad driver status: 0x%x", io_hdr.driver_status); + return FALSE; + } + + /* repopulate ata_tf */ + tf->error = sb[8 + 3]; + tf->nsect = sb[8 + 5]; + tf->lbal = sb[8 + 7]; + tf->lbam = sb[8 + 9]; + tf->lbah = sb[8 + 11]; + tf->dev = sb[8 + 12]; + tf->status = sb[8 + 13]; + g_debug ("ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x", + io_hdr.cmd_len, tf->status, tf->error, tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->dev); + + /* io error */ + if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "I/O error, ata_op=0x%02x ata_status=0x%02x ata_error=0x%02x", + tf->command, tf->status, tf->error); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_setup (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + struct ata_tf tf = { 0x0 }; + guint8 id[FU_ATA_IDENTIFY_SIZE]; + + /* get ID block */ + tf.dev = ATA_USING_LBA; + tf.command = ATA_OP_IDENTIFY; + tf.nsect = 1; /* 512 bytes */ + if (!fu_ata_device_command (self, &tf, SG_DXFER_FROM_DEV, 1000, + id, sizeof(id), error)) { + g_prefix_error (error, "failed to IDENTIFY"); + return FALSE; + } + if (!fu_ata_device_parse_id (self, id, sizeof(id), error)) + return FALSE; + + /* add the name fallback */ + fu_device_add_guid (device, fu_device_get_name (device)); + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_close (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + if (!g_close (self->fd, error)) + return FALSE; + self->fd = 0; + return TRUE; +} + +static gboolean +fu_ata_device_fw_download (FuAtaDevice *self, + guint32 idx, + guint32 addr, + const guint8 *data, + guint32 data_sz, + GError **error) +{ + struct ata_tf tf = { 0x0 }; + guint32 block_count = data_sz / FU_ATA_BLOCK_SIZE; + guint32 buffer_offset = addr / FU_ATA_BLOCK_SIZE; + + /* write block */ + tf.dev = 0xa0 | ATA_USING_LBA; + tf.command = ATA_OP_DOWNLOAD_MICROCODE; + tf.feat = self->transfer_mode; + tf.nsect = block_count & 0xff; + tf.lbal = block_count >> 8; + tf.lbam = buffer_offset & 0xff; + tf.lbah = buffer_offset >> 8; + if (!fu_ata_device_command (self, &tf, SG_DXFER_TO_DEV, + 120 * 1000, /* a long time! */ + (guint8 *) data, data_sz, error)) { + g_prefix_error (error, "failed to write firmware @0x%0x", + (guint) addr); + return FALSE; + } + + /* check drive status */ + if (tf.nsect == 0x0) + return TRUE; + + /* drive wants more data, or thinks it is all done */ + if (tf.nsect == 0x1 || tf.nsect == 0x2) + return TRUE; + + /* the offset was set up incorrectly */ + if (tf.nsect == 0x4) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "alignment error"); + return FALSE; + } + + /* other error */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unknown return code 0x%02x", + tf.nsect); + return FALSE; +} + +static gboolean +fu_ata_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + guint32 chunksz = (guint32) self->transfer_blocks * FU_ATA_BLOCK_SIZE; + guint max_size = 0xffff * FU_ATA_BLOCK_SIZE; + g_autoptr(GPtrArray) chunks = NULL; + + /* only one block allowed */ + if (self->transfer_mode == 0x7) + max_size = 0xffff; + + /* check is valid */ + if (g_bytes_get_size (fw) > max_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware is too large, maximum size is %u", + max_size); + return FALSE; + } + if (g_bytes_get_size (fw) % FU_ATA_BLOCK_SIZE != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware is not multiple of block size %i", + FU_ATA_BLOCK_SIZE); + return FALSE; + } + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, 0x00, 0x00, chunksz); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_ata_device_fw_download (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) { + g_prefix_error (error, "failed to write chunk %u: ", i); + return FALSE; + } + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len + 1); + } + + /* success! */ + fu_device_set_progress (device, 100); + return TRUE; +} + +static gboolean +fu_ata_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + if (g_strcmp0 (key, "AtaTransferMode") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp != 0x3 && tmp != 0x7 && tmp != 0xe) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "AtaTransferMode only supports " + "values 0x3, 0x7 or 0xe"); + return FALSE; + } + self->transfer_mode = (guint8) tmp; + return TRUE; + } + if (g_strcmp0 (key, "AtaTransferBlocks") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "AtaTransferBlocks only supports " + "values <= 0xffff"); + return FALSE; + } + self->transfer_blocks = (guint16) tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_ata_device_init (FuAtaDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_summary (FU_DEVICE (self), "ATA Drive"); + fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); +} + +static void +fu_ata_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_ata_device_parent_class)->finalize (object); +} + +static void +fu_ata_device_class_init (FuAtaDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_ata_device_finalize; + klass_device->to_string = fu_ata_device_to_string; + klass_device->set_quirk_kv = fu_ata_device_set_quirk_kv; + klass_device->open = fu_ata_device_open; + klass_device->setup = fu_ata_device_setup; + klass_device->close = fu_ata_device_close; + klass_device->write_firmware = fu_ata_device_write_firmware; + klass_udev_device->probe = fu_ata_device_probe; +} + +FuAtaDevice * +fu_ata_device_new (FuUdevDevice *device) +{ + FuAtaDevice *self = g_object_new (FU_TYPE_ATA_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} + +FuAtaDevice * +fu_ata_device_new_from_blob (const guint8 *buf, gsize sz, GError **error) +{ + g_autoptr(FuAtaDevice) self = g_object_new (FU_TYPE_ATA_DEVICE, NULL); + if (!fu_ata_device_parse_id (self, buf, sz, error)) + return NULL; + return g_steal_pointer (&self); +} diff --git a/plugins/ata/fu-ata-device.h b/plugins/ata/fu-ata-device.h new file mode 100644 index 000000000..ce0619aa4 --- /dev/null +++ b/plugins/ata/fu-ata-device.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_ATA_DEVICE_H +#define __FU_ATA_DEVICE_H + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_ATA_DEVICE (fu_ata_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuAtaDevice, fu_ata_device, FU, ATA_DEVICE, FuUdevDevice) + +FuAtaDevice *fu_ata_device_new (FuUdevDevice *device); +FuAtaDevice *fu_ata_device_new_from_blob (const guint8 *buf, + gsize sz, + GError **error); + +/* for self tests */ +guint8 fu_ata_device_get_transfer_mode (FuAtaDevice *self); +guint16 fu_ata_device_get_transfer_blocks (FuAtaDevice *self); + +G_END_DECLS + +#endif /* __FU_ATA_DEVICE_H */ diff --git a/plugins/ata/fu-plugin-ata.c b/plugins/ata/fu-plugin-ata.c new file mode 100644 index 000000000..9a8ab1c34 --- /dev/null +++ b/plugins/ata/fu-plugin-ata.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-ata-device.h" + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + GUdevDevice *udev_device = fu_udev_device_get_dev (device); + g_autoptr(FuAtaDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* interesting device? */ + if (udev_device == NULL) + return TRUE; + if (g_strcmp0 (g_udev_device_get_subsystem (udev_device), "block") != 0) + return TRUE; + if (g_strcmp0 (g_udev_device_get_devtype (udev_device), "disk") != 0) + return TRUE; + if (!g_udev_device_get_property_as_boolean (udev_device, "ID_ATA_SATA")) + return TRUE; + if (!g_udev_device_get_property_as_boolean (udev_device, "ID_ATA_DOWNLOAD_MICROCODE")) + return TRUE; + + dev = fu_ata_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "block"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.t13.ata"); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, error); +} diff --git a/plugins/ata/fu-self-test.c b/plugins/ata/fu-self-test.c new file mode 100644 index 000000000..805cf90a0 --- /dev/null +++ b/plugins/ata/fu-self-test.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-ata-device.h" +#include "fu-test.h" + +static void +fu_ata_id_func (void) +{ + gboolean ret; + gsize sz; + g_autofree gchar *data = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAtaDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + path = fu_test_get_filename (TESTDATADIR, "StarDrive-SBFM61.2.bin"); + g_assert_nonnull (path); + ret = g_file_get_contents (path, &data, &sz, &error); + g_assert_no_error (error); + g_assert (ret); + dev = fu_ata_device_new_from_blob ((guint8 *)data, sz, &error); + g_assert_no_error (error); + g_assert_nonnull (dev); + g_assert_cmpint (fu_ata_device_get_transfer_mode (dev), ==, 0x3); + g_assert_cmpint (fu_ata_device_get_transfer_blocks (dev), ==, 0x1); + g_assert_cmpstr (fu_device_get_serial (FU_DEVICE (dev)), ==, "A45A078A198600476509"); + g_assert_cmpstr (fu_device_get_name (FU_DEVICE (dev)), ==, "SATA SSD"); + g_assert_cmpstr (fu_device_get_version (FU_DEVICE (dev)), ==, "SBFM61.2"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/fwupd/id", fu_ata_id_func); + return g_test_run (); +} diff --git a/plugins/ata/meson.build b/plugins/ata/meson.build new file mode 100644 index 000000000..cd26e395d --- /dev/null +++ b/plugins/ata/meson.build @@ -0,0 +1,58 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginAta"'] + +install_data([ + 'ata.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_ata', + fu_hash, + sources : [ + 'fu-plugin-ata.c', + 'fu-ata-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + link_with : [ + libfwupdprivate, + ], + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'ata-self-test', + sources : [ + 'fu-self-test.c', + 'fu-ata-device.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../..'), + include_directories('../../libfwupd'), + include_directories('../../src'), + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + libfwupdprivate, + ], + c_args : cargs + ) + test('ata-self-test', e) +endif diff --git a/plugins/ata/tests/StarDrive-SBFM61.2.bin b/plugins/ata/tests/StarDrive-SBFM61.2.bin new file mode 100644 index 0000000000000000000000000000000000000000..201cceca295cd57a8d3e4d840d5527291e4a1352 GIT binary patch literal 512 zcmZ=@_-}81LVy7T?7<`hgNdV~skwopg{7gHg@J*&iK&^T0Yu6v*w@X_%t+5M*fAtn z!6jIM01#+kaA42}Vjy4#+9Uw9L*UPE1_8$Z|NrxY#F!Z>ppZcxVh4znXW(mPWAI^c zVfX=5m0iMEo9vib!nh~dvEG4;K@O Date: Wed, 30 Jan 2019 11:11:50 +0000 Subject: [PATCH 231/254] ata: Mark all devices as needing a reboot Although not strictly required, I would feel a lot more warm and fuzzy knowing the drives are running the new firmware ASAP. --- plugins/ata/fu-ata-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/ata/fu-ata-device.c b/plugins/ata/fu-ata-device.c index c91bf514e..aaa2b7666 100644 --- a/plugins/ata/fu-ata-device.c +++ b/plugins/ata/fu-ata-device.c @@ -573,6 +573,7 @@ fu_ata_device_init (FuAtaDevice *self) { fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_set_summary (FU_DEVICE (self), "ATA Drive"); fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); } From 96019e815cda75c1ac0d6e5a44e9044776b34de3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 30 Jan 2019 11:12:57 +0000 Subject: [PATCH 232/254] trivial: Allow reflashing the same device more than once without restarting Set the device status back to the default when completed flashing so that we don't ignore the status change for the subsequent flash. --- src/fu-engine.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index 353c345cc..a7fac5f87 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -1269,6 +1269,13 @@ 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); + fu_device_set_status (device, FWUPD_STATUS_UNKNOWN); + } + /* get a new list of devices in case they replugged */ devices_new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < devices->len; i++) { From 2a77afcd5c25d55ed7e694baccc535737d69a00d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 30 Jan 2019 11:19:48 +0000 Subject: [PATCH 233/254] trivial: Do not propagate UNKNOWN from FuDevice->FuEngine->FuMain --- src/fu-engine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fu-engine.c b/src/fu-engine.c index a7fac5f87..d99054f56 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -144,6 +144,8 @@ fu_engine_set_percentage (FuEngine *self, guint percentage) static void fu_engine_progress_notify_cb (FuDevice *device, GParamSpec *pspec, FuEngine *self) { + if (fu_device_get_status (device) == FWUPD_STATUS_UNKNOWN) + return; fu_engine_set_percentage (self, fu_device_get_progress (device)); fu_engine_emit_device_changed (self, device); } From 44ce5aeae4a07fc661ecf1fae37aaa073c4b881c Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 18 Jan 2019 09:51:47 +0000 Subject: [PATCH 234/254] uefi: Add a quirk to use the legacy bootmgr description Some hardware from Lenovo deduplicates UEFI Boot entries, and uses the old string 'Linux-Firmware-Updater' to avoid removing the firmware update entry. Although this is forbidden in the UEFI specification we shouldn't break firmware updates from old firmware versions. Provide a quirk for this, and automatically whitelist anything with the LENOVO SMBIOS Manufacturer. --- plugins/uefi/fu-plugin-uefi.c | 6 ++++++ plugins/uefi/fu-uefi-bootmgr.c | 7 +++++-- plugins/uefi/fu-uefi-bootmgr.h | 1 + plugins/uefi/fu-uefi-device.c | 7 ++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 26a0b053f..17720d3ac 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -511,6 +511,12 @@ fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **er if (!fu_device_probe (FU_DEVICE (dev), error)) return FALSE; + /* set this flag for all Lenovo hardware */ + if (fu_plugin_check_hwid (plugin, "6de5d951-d755-576b-bd09-c5cf66b27234")) { + fu_device_set_custom_flags (FU_DEVICE (dev), "use-legacy-bootmgr-desc"); + fu_plugin_add_report_metadata (plugin, "BootMgrDesc", "legacy"); + } + /* set fallback name if nothing else is set */ if (fu_device_get_name (FU_DEVICE (dev)) == 0) { g_autofree gchar *name = NULL; diff --git a/plugins/uefi/fu-uefi-bootmgr.c b/plugins/uefi/fu-uefi-bootmgr.c index 76834dfe2..a67ea1499 100644 --- a/plugins/uefi/fu-uefi-bootmgr.c +++ b/plugins/uefi/fu-uefi-bootmgr.c @@ -292,7 +292,10 @@ fu_uefi_copy_asset (const gchar *source, const gchar *target, GError **error) } gboolean -fu_uefi_bootmgr_bootnext (const gchar *esp_path, FuUefiBootmgrFlags flags, GError **error) +fu_uefi_bootmgr_bootnext (const gchar *esp_path, + const gchar *description, + FuUefiBootmgrFlags flags, + GError **error) { gboolean use_fwup_path = FALSE; gsize loader_sz = 0; @@ -382,7 +385,7 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path, FuUefiBootmgrFlags flags, GErro return FALSE; } - label = g_strdup ("Linux Firmware Updater"); + label = g_strdup (description); sz = efi_loadopt_create (opt, opt_size, attributes, (efidp)dp_buf, dp_size, (guint8 *)label, diff --git a/plugins/uefi/fu-uefi-bootmgr.h b/plugins/uefi/fu-uefi-bootmgr.h index 34c9049b4..07622cd67 100644 --- a/plugins/uefi/fu-uefi-bootmgr.h +++ b/plugins/uefi/fu-uefi-bootmgr.h @@ -20,6 +20,7 @@ typedef enum { } FuUefiBootmgrFlags; gboolean fu_uefi_bootmgr_bootnext (const gchar *esp_path, + const gchar *description, FuUefiBootmgrFlags flags, GError **error); diff --git a/plugins/uefi/fu-uefi-device.c b/plugins/uefi/fu-uefi-device.c index ff41e1d47..34bc4ac0d 100644 --- a/plugins/uefi/fu-uefi-device.c +++ b/plugins/uefi/fu-uefi-device.c @@ -353,6 +353,7 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) { FuUefiDevice *self = FU_UEFI_DEVICE (device); FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE; + const gchar *bootmgr_desc = "Linux Firmware Updater"; const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); efi_guid_t guid; efi_update_info_t info; @@ -423,7 +424,11 @@ fu_uefi_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) /* update the firmware before the bootloader runs */ if (fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")) flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB; - if (!fu_uefi_bootmgr_bootnext (esp_path, flags, error)) + + /* some legacy devices use the old name to deduplicate boot entries */ + if (fu_device_has_custom_flag (device, "use-legacy-bootmgr-desc")) + bootmgr_desc = "Linux-Firmware-Updater"; + if (!fu_uefi_bootmgr_bootnext (esp_path, bootmgr_desc, flags, error)) return FALSE; /* success! */ From 046c84b5b37d4d60ad3151d8d7b05da74ebe04aa Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Mon, 28 Jan 2019 23:20:45 +0100 Subject: [PATCH 235/254] fastboot: flash the partition after downloading the file --- plugins/fastboot/fu-fastboot-device.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/plugins/fastboot/fu-fastboot-device.c b/plugins/fastboot/fu-fastboot-device.c index f4674ae27..904fd6e1f 100644 --- a/plugins/fastboot/fu-fastboot-device.c +++ b/plugins/fastboot/fu-fastboot-device.c @@ -251,10 +251,19 @@ fu_fastboot_device_cmd (FuDevice *device, const gchar *cmd, GError **error) } static gboolean -fu_fastboot_device_flash (FuDevice *device, - const gchar *partition, - GBytes *fw, - GError **error) +fu_fastboot_device_flash (FuDevice *device, const gchar *partition, GError **error) +{ + g_autofree gchar *tmp = g_strdup_printf ("flash:%s", partition); + if (!fu_fastboot_device_writestr (device, tmp, error)) + return FALSE; + if (!fu_fastboot_device_read (device, NULL, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_download (FuDevice *device, GBytes *fw, GError **error) { FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); gsize sz = g_bytes_get_size (fw); @@ -360,7 +369,9 @@ fu_fastboot_device_write_qfil_part (FuDevice *device, partition += 2; /* flash the partition */ - return fu_fastboot_device_flash (device, partition, data, error); + if (!fu_fastboot_device_download (device, data, error)) + return FALSE; + return fu_fastboot_device_flash (device, partition, error); } static gboolean @@ -481,7 +492,9 @@ fu_fastboot_device_write_motorola_part (FuDevice *device, } /* flash the partition */ - return fu_fastboot_device_flash (device, partition, data, error); + if (!fu_fastboot_device_download (device, data, error)) + return FALSE; + return fu_fastboot_device_flash (device, partition, error); } /* dumb operation that doesn't expect a response */ From b9b6834f54db53235ed09b34a52ab032685409f3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 29 Jan 2019 09:32:48 +0000 Subject: [PATCH 236/254] trivial: Add FuFastbootDeviceReadFlags to fu_fastboot_device_cmd() --- plugins/fastboot/fu-fastboot-device.c | 34 ++++++++++++++------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/plugins/fastboot/fu-fastboot-device.c b/plugins/fastboot/fu-fastboot-device.c index 904fd6e1f..cd26d59bd 100644 --- a/plugins/fastboot/fu-fastboot-device.c +++ b/plugins/fastboot/fu-fastboot-device.c @@ -240,12 +240,12 @@ fu_fastboot_device_getvar (FuDevice *device, const gchar *key, gchar **str, GErr } static gboolean -fu_fastboot_device_cmd (FuDevice *device, const gchar *cmd, GError **error) +fu_fastboot_device_cmd (FuDevice *device, const gchar *cmd, + FuFastbootDeviceReadFlags flags, GError **error) { if (!fu_fastboot_device_writestr (device, cmd, error)) return FALSE; - if (!fu_fastboot_device_read (device, NULL, - FU_FASTBOOT_DEVICE_READ_FLAG_NONE, error)) + if (!fu_fastboot_device_read (device, NULL, flags, error)) return FALSE; return TRUE; } @@ -254,12 +254,9 @@ static gboolean fu_fastboot_device_flash (FuDevice *device, const gchar *partition, GError **error) { g_autofree gchar *tmp = g_strdup_printf ("flash:%s", partition); - if (!fu_fastboot_device_writestr (device, tmp, error)) - return FALSE; - if (!fu_fastboot_device_read (device, NULL, - FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, error)) - return FALSE; - return TRUE; + return fu_fastboot_device_cmd (device, tmp, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, + error); } static gboolean @@ -271,10 +268,9 @@ fu_fastboot_device_download (FuDevice *device, GBytes *fw, GError **error) g_autoptr(GPtrArray) chunks = NULL; /* tell the client the size of data to expect */ - if (!fu_fastboot_device_writestr (device, tmp, error)) - return FALSE; - if (!fu_fastboot_device_read (device, NULL, - FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, error)) + if (!fu_fastboot_device_cmd (device, tmp, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, + error)) return FALSE; /* send the data in chunks */ @@ -436,7 +432,9 @@ fu_fastboot_device_write_motorola_part (FuDevice *device, } /* erase the partition */ - return fu_fastboot_device_cmd (device, cmd, error); + return fu_fastboot_device_cmd (device, cmd, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); } /* flash */ @@ -503,7 +501,9 @@ fu_fastboot_device_write_motorola_part (FuDevice *device, g_strcmp0 (op, "reboot") == 0 || g_strcmp0 (op, "reboot-bootloader") == 0 || g_strcmp0 (op, "powerdown") == 0) { - return fu_fastboot_device_cmd (device, op, error); + return fu_fastboot_device_cmd (device, op, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); } /* unknown */ @@ -672,7 +672,9 @@ static gboolean fu_fastboot_device_attach (FuDevice *device, GError **error) { fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); - return fu_fastboot_device_cmd (device, "reboot", error); + return fu_fastboot_device_cmd (device, "reboot", + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); } static void From 52b9800744663ac0510bfebb4d6ba6a6d509d722 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 30 Jan 2019 13:09:54 +0000 Subject: [PATCH 237/254] wacom-usb: Fix the plugin name to allow devices to be updated --- plugins/wacom-usb/wacom-usb.quirk | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/wacom-usb/wacom-usb.quirk b/plugins/wacom-usb/wacom-usb.quirk index 59423a0cd..ac229566b 100644 --- a/plugins/wacom-usb/wacom-usb.quirk +++ b/plugins/wacom-usb/wacom-usb.quirk @@ -1,58 +1,58 @@ # Intuos Pro medium (2nd-gen BT) [PTH-660] [DeviceInstanceId=USB\VID_056A&PID_0360] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos Pro large (2nd-gen BT) [PTH-860] [DeviceInstanceId=USB\VID_056A&PID_0361] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos BT S (3rd-gen BT) [CTL-4100WL] [DeviceInstanceId=USB\VID_056A&PID_0377] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos BT M (3rd-gen BT) [CTL-6100WL] [DeviceInstanceId=USB\VID_056A&PID_0379] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos Pro medium (2nd-gen USB) [PTH-660] [DeviceInstanceId=USB\VID_056A&PID_0357] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos Pro large (2nd-gen USB) [PTH-860] [DeviceInstanceId=USB\VID_056A&PID_0358] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos S 3rd-gen (USB) [CTL-4100] [DeviceInstanceId=USB\VID_056A&PID_0374] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos M 3rd-gen (USB) [NA] [DeviceInstanceId=USB\VID_056A&PID_0375] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos BT S 3rd-gen (USB) [CTL-4100WL] [DeviceInstanceId=USB\VID_056A&PID_0376] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos BT M 3rd-gen (USB) [CTL-6100WL] [DeviceInstanceId=USB\VID_056A&PID_0378] -Plugin = wacom-usb +Plugin = wacom_usb Flags = use-runtime-version # Intuos Pro Small (2nd-gen USB) [PTH-460] [DeviceInstanceId=USB\VID_056A&PID_0392] -Plugin = wacom-usb +Plugin = wacom_usb # Intuos Pro Small (2nd-gen Bluetooth) [PTH-460] [DeviceInstanceId=USB\VID_056A&PID_0393] -Plugin = wacom-usb +Plugin = wacom_usb From 423dde520cde468bc51f791ee95e0439975c1305 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 30 Jan 2019 10:35:08 -0600 Subject: [PATCH 238/254] dell: Check that the flash interface command is available This prevents the kernel showing errors when running on systems without this command. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=202259 --- plugins/dell/fu-plugin-dell.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index d15228040..274dbe80d 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -45,6 +45,16 @@ typedef struct _DOCK_DESCRIPTION const gchar * desc; } DOCK_DESCRIPTION; +struct da_structure { + guint8 type; + guint8 length; + guint16 handle; + guint16 cmd_address; + guint8 cmd_code; + guint32 supported_cmds; + guint8 *tokens; +} __attribute__((packed)); + /* These are for matching the components */ #define WD15_EC_STR "2 0 2 2 0" #define TB16_EC_STR "2 0 2 1 0" @@ -159,8 +169,10 @@ static gboolean fu_dell_supported (FuPlugin *plugin) { GBytes *de_table = NULL; + GBytes *da_table = NULL; GBytes *enclosure = NULL; const guint8 *value; + const struct da_structure *da_values; gsize len; /* make sure that Dell SMBIOS methods are available */ @@ -172,6 +184,17 @@ fu_dell_supported (FuPlugin *plugin) return FALSE; if (*value != 0xDE) return FALSE; + da_table = fu_plugin_get_smbios_data (plugin, 0xDA); + if (da_table == NULL) + return FALSE; + da_values = (struct da_structure *) g_bytes_get_data (da_table, &len); + if (len == 0) + return FALSE; + if (!(da_values->supported_cmds & (1 << DACI_FLASH_INTERFACE_CLASS))) { + g_debug ("unable to access flash interface. supported commands: 0x%x", + da_values->supported_cmds); + return FALSE; + } /* only run on intended Dell hw types */ enclosure = fu_plugin_get_smbios_data (plugin, From 769f990cf6937e4e270aef1bbefa2283121b8725 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 30 Jan 2019 10:37:06 -0600 Subject: [PATCH 239/254] trivial: dell: filter another dock SKU from this plugin Prevents showing errors in the logs --- plugins/dell/fu-plugin-dell.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 274dbe80d..a10c841ee 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -65,6 +65,7 @@ struct da_structure { #define UNIV_CBL_STR "2 2 2 2 0" #define TBT_CBL_STR "2 2 2 3 0" #define FUTURE_EC_STR "3 0 2 4 0" +#define FUTURE_EC_STR2 "4 0 2 4 0" /* supported dock related GUIDs */ #define DOCK_FLASH_GUID "e7ca1f36-bf73-4574-afe6-a4ccacabf479" @@ -227,6 +228,7 @@ fu_plugin_dell_match_dock_component (const gchar *query_str, {UNIV_CBL_GUID, UNIV_CBL_STR, UNIV_CBL_DESC}, {LEGACY_CBL_GUID, LEGACY_CBL_STR, LEGACY_CBL_DESC}, {NULL, FUTURE_EC_STR, NULL}, + {NULL, FUTURE_EC_STR2, NULL}, }; for (guint i = 0; i < G_N_ELEMENTS (list); i++) { From 19968a756d23218d1cb9f77a63eab7268488371d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 30 Jan 2019 15:01:52 -0600 Subject: [PATCH 240/254] fu-keyring-utils: Don't fail missing PKI directory when compiled with GPG/PKCS7 This directory won't be installed when compiled without those. --- src/fu-keyring-utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fu-keyring-utils.c b/src/fu-keyring-utils.c index a3f1936a7..12c8d0bd4 100644 --- a/src/fu-keyring-utils.c +++ b/src/fu-keyring-utils.c @@ -135,6 +135,7 @@ fu_keyring_get_release_trust_flags (XbNode *release, /* check we were installed correctly */ sysconfdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); pki_dir = g_build_filename (sysconfdir, "pki", PACKAGE_NAME, NULL); +#if defined(ENABLE_PKCS7) || defined(ENABLE_PKCS7) if (!g_file_test (pki_dir, G_FILE_TEST_EXISTS)) { g_set_error (error, FWUPD_ERROR, @@ -142,6 +143,7 @@ fu_keyring_get_release_trust_flags (XbNode *release, "PKI directory %s not found", pki_dir); return FALSE; } +#endif /* verify against the system trusted keys */ kr = fu_keyring_create_for_kind (keyring_kind, error); From a3b13046c28dbc6535d470a22d596038703188db Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 31 Jan 2019 11:55:12 +0000 Subject: [PATCH 241/254] wacom-usb: Add some more information to the README --- plugins/wacom-usb/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/wacom-usb/README.md b/plugins/wacom-usb/README.md index 83fad5d53..e4bc759b8 100644 --- a/plugins/wacom-usb/README.md +++ b/plugins/wacom-usb/README.md @@ -20,7 +20,12 @@ Firmware Format --------------- The daemon will decompress the cabinet archive and extract a firmware blob in -SREC file format, with a custom vendor header. +the following formats: + + * Touch module: Intel HEX file format + * Bluetooth module: Unknown airoflash file format + * EMR module: Plain SREC file format + * Main module: SREC file format, with a custom `WACOM` vendor header This plugin supports the following protocol ID: From c1fad937d8a4c2dfdf162ed640ad4a41f4311828 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 31 Jan 2019 11:55:46 +0000 Subject: [PATCH 242/254] wacom-raw: Use the correct error codes when the panel is not supported Otherwise, we get a nasty red console warning when plugging in a *USB* panel. --- plugins/wacom-raw/fu-plugin-wacom-raw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/wacom-raw/fu-plugin-wacom-raw.c b/plugins/wacom-raw/fu-plugin-wacom-raw.c index d1e72456d..22e4882f4 100644 --- a/plugins/wacom-raw/fu-plugin-wacom-raw.c +++ b/plugins/wacom-raw/fu-plugin-wacom-raw.c @@ -75,8 +75,8 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er /* not supported */ g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, "Only EMR or AES devices are supported"); return FALSE; } From ccc79c9fbc8cbd9eee511a1285c71ad27bc77419 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 31 Jan 2019 14:30:36 +0000 Subject: [PATCH 243/254] trivial: Split out strnsplit for future use --- plugins/dfu/dfu-common.c | 24 ++++++++++++++++++++++++ plugins/dfu/dfu-common.h | 4 ++++ plugins/dfu/dfu-format-ihex.c | 13 +------------ 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/plugins/dfu/dfu-common.c b/plugins/dfu/dfu-common.c index fd5173cfb..9e747872c 100644 --- a/plugins/dfu/dfu-common.c +++ b/plugins/dfu/dfu-common.c @@ -326,3 +326,27 @@ dfu_utils_buffer_parse_uint32 (const gchar *data) buffer[8] = '\0'; return (guint32) g_ascii_strtoull (buffer, NULL, 16); } + +/** + * dfu_utils_strnsplit: + * @str: a string to split + * @sz: size of @str + * @delimiter: a string which specifies the places at which to split the string + * @max_tokens: the maximum number of pieces to split @str into + * + * Splits a string into a maximum of @max_tokens pieces, using the given + * delimiter. If @max_tokens is reached, the remainder of string is appended + * to the last token. + * + * Return value: a newly-allocated NULL-terminated array of strings + **/ +gchar ** +dfu_utils_strnsplit (const gchar *str, gsize sz, + const gchar *delimiter, gint max_tokens) +{ + if (str[sz - 1] != '\0') { + g_autofree gchar *str2 = g_strndup (str, sz); + return g_strsplit (str2, delimiter, max_tokens); + } + return g_strsplit (str, delimiter, max_tokens); +} diff --git a/plugins/dfu/dfu-common.h b/plugins/dfu/dfu-common.h index b51dfadec..09c54a97c 100644 --- a/plugins/dfu/dfu-common.h +++ b/plugins/dfu/dfu-common.h @@ -165,6 +165,10 @@ guint8 dfu_utils_buffer_parse_uint8 (const gchar *data); guint16 dfu_utils_buffer_parse_uint16 (const gchar *data); guint32 dfu_utils_buffer_parse_uint24 (const gchar *data); guint32 dfu_utils_buffer_parse_uint32 (const gchar *data); +gchar **dfu_utils_strnsplit (const gchar *str, + gsize sz, + const gchar *delimiter, + gint max_tokens); G_END_DECLS diff --git a/plugins/dfu/dfu-format-ihex.c b/plugins/dfu/dfu-format-ihex.c index 3fcf78dba..35acaa393 100644 --- a/plugins/dfu/dfu-format-ihex.c +++ b/plugins/dfu/dfu-format-ihex.c @@ -74,17 +74,6 @@ dfu_firmware_ihex_record_type_to_string (guint8 record_type) return NULL; } -static gchar ** -_g_strnsplit (const gchar *str, gsize sz, - const gchar *delimiter, gint max_tokens) -{ - if (str[sz - 1] != '\0') { - g_autofree gchar *str2 = g_strndup (str, sz); - return g_strsplit (str2, delimiter, max_tokens); - } - return g_strsplit (str, delimiter, max_tokens); -} - /** * dfu_firmware_from_ihex: (skip) * @firmware: a #DfuFirmware @@ -125,7 +114,7 @@ dfu_firmware_from_ihex (DfuFirmware *firmware, /* parse records */ data = g_bytes_get_data (bytes, &sz); - lines = _g_strnsplit ((const gchar *) data, sz, "\n", -1); + lines = dfu_utils_strnsplit (data, sz, "\n", -1); for (guint ln = 0; lines[ln] != NULL; ln++) { const gchar *line = lines[ln]; gsize linesz; From 206b70120da23c0475fa6a7345ba7ae3b8ef4b91 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 31 Jan 2019 14:31:52 +0000 Subject: [PATCH 244/254] dfu: Simplify the SREC parser to avoid a crash with an invalid file Splitting the file into lines does increase memory usage, but allows us to use a much simpler parser design. This is just like we fixed IHEX a few weeks ago. --- plugins/dfu/dfu-format-srec.c | 228 +++++++++++++++++----------------- 1 file changed, 112 insertions(+), 116 deletions(-) diff --git a/plugins/dfu/dfu-format-srec.c b/plugins/dfu/dfu-format-srec.c index b99623cac..df239a65b 100644 --- a/plugins/dfu/dfu-format-srec.c +++ b/plugins/dfu/dfu-format-srec.c @@ -38,15 +38,6 @@ dfu_firmware_detect_srec (GBytes *bytes) return DFU_FIRMWARE_FORMAT_SREC; } -typedef enum { - DFU_SREC_RECORD_CLASS_UNKNOWN, - DFU_SREC_RECORD_CLASS_HEADER, - DFU_SREC_RECORD_CLASS_DATA, - DFU_SREC_RECORD_CLASS_TERMINATION, - DFU_SREC_RECORD_CLASS_COUNT, - DFU_SREC_RECORD_CLASS_LAST -} DfuSrecClassType; - /** * dfu_firmware_from_srec: (skip) * @firmware: a #DfuFirmware @@ -65,65 +56,67 @@ dfu_image_from_srec (DfuImage *image, DfuFirmwareParseFlags flags, GError **error) { - const gchar *in_buffer; + const gchar *data; gboolean got_eof = FALSE; gboolean got_hdr = FALSE; - gsize len_in; - guint16 class_data_cnt = 0; + gsize sz = 0; + guint16 data_cnt = 0; guint32 addr32_last = 0; guint32 element_address = 0; - guint offset = 0; - g_autoptr(DfuElement) element = NULL; + g_auto(GStrv) lines = NULL; + g_autoptr(DfuElement) element = dfu_element_new (); g_autoptr(GBytes) contents = NULL; - g_autoptr(GString) modname = g_string_new (NULL); - g_autoptr(GString) outbuf = NULL; + g_autoptr(GString) outbuf = g_string_new (NULL); g_return_val_if_fail (bytes != NULL, FALSE); - /* create element */ - element = dfu_element_new (); - /* parse records */ - in_buffer = g_bytes_get_data (bytes, &len_in); - outbuf = g_string_new (""); - while (offset < len_in) { - DfuSrecClassType rec_class = DFU_SREC_RECORD_CLASS_UNKNOWN; + data = g_bytes_get_data (bytes, &sz); + lines = dfu_utils_strnsplit (data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; guint32 rec_addr32; - guint8 rec_count; /* bytes */ - guint8 rec_dataoffset; /* bytes */ + guint8 addrsz = 0; /* bytes */ + guint8 rec_count; /* words */ guint8 rec_kind; + /* ignore blank lines */ + g_strdelimit (lines[ln], "\r", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; + /* check starting token */ - if (in_buffer[offset] != 'S') { + if (line[0] != 'S') { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid starting token, got 0x%02x at 0x%x", - (guint) in_buffer[offset], offset); + "invalid starting token, got '%c' at line %u", + line[0], ln); return FALSE; } /* check there's enough data for the smallest possible record */ - if (offset + 10 > (guint) len_in) { + if (linesz < 10) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "record incomplete at %u, length %u", - offset, (guint) len_in); + "record incomplete at line %u, length %u", + ln, (guint) linesz); return FALSE; } /* kind, count, address, (data), checksum, linefeed */ - rec_kind = in_buffer[offset + 1]; - rec_count = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 2); - - /* check we can read out this much data */ - if (len_in < offset + (rec_count * 2) + 4) { + rec_kind = line[1] - '0'; + rec_count = dfu_utils_buffer_parse_uint8 (line + 2); + if (rec_count * 2 != linesz - 4) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "file incomplete at %u, length %u", - offset, (guint) len_in); + "count incomplete at line %u, " + "length %u, expected %u", + ln, (guint) linesz - 4, (guint) rec_count * 2); return FALSE; } @@ -132,28 +125,24 @@ dfu_image_from_srec (DfuImage *image, guint8 rec_csum = 0; guint8 rec_csum_expected; for (guint8 i = 0; i < rec_count; i++) - rec_csum += dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2) + 2); + rec_csum += dfu_utils_buffer_parse_uint8 (line + (i * 2) + 2); rec_csum ^= 0xff; - rec_csum_expected = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (rec_count * 2) + 2); + rec_csum_expected = dfu_utils_buffer_parse_uint8 (line + (rec_count * 2) + 2); if (rec_csum != rec_csum_expected) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "checksum incorrect @ 0x%04x, expected %02x, got %02x", - offset, rec_csum_expected, rec_csum); + "checksum incorrect line %u, " + "expected %02x, got %02x", + ln, rec_csum_expected, rec_csum); return FALSE; } } - /* record kind + record count (in bytes, not chars) */ - rec_dataoffset = 2; - - /* parse record */ + /* set each command settings */ switch (rec_kind) { - case '0': - rec_class = DFU_SREC_RECORD_CLASS_HEADER; - rec_dataoffset += 2; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); + case 0: + addrsz = 2; if (got_hdr) { g_set_error_literal (error, FWUPD_ERROR, @@ -161,6 +150,63 @@ dfu_image_from_srec (DfuImage *image, "duplicate header record"); return FALSE; } + got_hdr = TRUE; + break; + case 1: + addrsz = 2; + break; + case 2: + addrsz = 3; + break; + case 3: + addrsz = 4; + break; + case 5: + addrsz = 2; + got_eof = TRUE; + break; + case 6: + addrsz = 3; + break; + case 7: + addrsz = 4; + got_eof = TRUE; + break; + case 8: + addrsz = 3; + got_eof = TRUE; + break; + case 9: + addrsz = 2; + got_eof = TRUE; + break; + default: + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid srec record type S%c", + line[1]); + return FALSE; + } + + /* parse address */ + switch (addrsz) { + case 2: + rec_addr32 = dfu_utils_buffer_parse_uint16 (line + 4); + break; + case 3: + rec_addr32 = dfu_utils_buffer_parse_uint24 (line + 4); + break; + case 4: + rec_addr32 = dfu_utils_buffer_parse_uint32 (line + 4); + break; + default: + g_assert_not_reached (); + } + + /* header */ + if (rec_kind == 0) { + g_autoptr(GString) modname = g_string_new (NULL); if (rec_addr32 != 0x0) { g_set_error (error, FWUPD_ERROR, @@ -169,76 +215,34 @@ dfu_image_from_srec (DfuImage *image, rec_addr32); return FALSE; } + /* could be anything, lets assume text */ - for (guint8 i = rec_dataoffset; i <= rec_count; i++) { - guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2)); + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); if (!g_ascii_isgraph (tmp)) break; g_string_append_c (modname, tmp); } if (modname->len != 0) dfu_image_set_name (image, modname->str); - got_hdr = TRUE; - break; - case '1': - rec_class = DFU_SREC_RECORD_CLASS_DATA; - rec_dataoffset += 2; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); - break; - case '2': - rec_class = DFU_SREC_RECORD_CLASS_DATA; - rec_dataoffset += 3; - rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4); - break; - case '3': - rec_class = DFU_SREC_RECORD_CLASS_DATA; - rec_dataoffset += 4; - rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4); - break; - case '9': - rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); - got_eof = TRUE; - break; - case '8': - rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; - rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4); - got_eof = TRUE; - break; - case '7': - rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; - rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4); - got_eof = TRUE; - break; - case '5': - rec_class = DFU_SREC_RECORD_CLASS_COUNT; - rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); - if (rec_addr32 != class_data_cnt) { + continue; + } + + /* verify we got all records */ + if (rec_kind == 5) { + if (rec_addr32 != data_cnt) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "count record was not valid, got 0x%02x expected 0x%02x", - (guint) rec_addr32, (guint) class_data_cnt); + (guint) rec_addr32, (guint) data_cnt); return FALSE; } - got_eof = TRUE; - break; - default: - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "invalid srec record type S%c", - rec_kind); - return FALSE; } - /* record EOF */ - if (rec_class == DFU_SREC_RECORD_CLASS_TERMINATION) - g_debug ("start execution location: 0x%04x", (guint) rec_addr32); - - /* read data */ - if (rec_class == DFU_SREC_RECORD_CLASS_DATA) { - /* probably invalid data */ + /* data */ + if (rec_kind == 1 || rec_kind == 2 || rec_kind == 3) { + /* invalid */ if (!got_hdr) { g_set_error_literal (error, FWUPD_ERROR, @@ -260,23 +264,15 @@ dfu_image_from_srec (DfuImage *image, g_debug ("ignoring data at 0x%x as before start address 0x%x", (guint) rec_addr32, (guint) start_addr); } else { - for (guint8 i = rec_dataoffset; i <= rec_count; i++) { - guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2)); + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); g_string_append_c (outbuf, tmp); } if (element_address == 0x0) element_address = rec_addr32; } addr32_last = rec_addr32++; - class_data_cnt++; - } - - /* ignore any line return */ - offset += (rec_count * 2) + 4; - for (; offset < len_in; offset++) { - if (in_buffer[offset] != '\n' && - in_buffer[offset] != '\r') - break; + data_cnt++; } } From ead0deaa255f08db0d777deb97f650d10d545eb5 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 30 Jan 2019 20:49:29 -0600 Subject: [PATCH 245/254] trivial: dell-dock: enable passive flow on all EC23+ The feature did land in EC23 and testing looks positive. --- plugins/dell-dock/README.md | 1 - plugins/dell-dock/fu-dell-dock-i2c-ec.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/dell-dock/README.md b/plugins/dell-dock/README.md index 00ecbee32..e363417da 100644 --- a/plugins/dell-dock/README.md +++ b/plugins/dell-dock/README.md @@ -53,7 +53,6 @@ Custom flag use: This plugin uses the following plugin-specific custom flags: * `skip-restart`: Don't run the reset or reboot procedure of the component -* `try-passive-flow`: Tries to use the "EC passive flow" delaying updates Quirk use --------- diff --git a/plugins/dell-dock/fu-dell-dock-i2c-ec.c b/plugins/dell-dock/fu-dell-dock-i2c-ec.c index e51537d31..7aa9e560e 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-ec.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-ec.c @@ -434,8 +434,7 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device, /* TODO: Drop if minimum EC is set to 23+ * Determine if the passive flow should be used when flashing */ - if (fu_device_has_custom_flag (device, "try-passive-flow") && - fu_common_vercmp (self->ec_version, "00.00.00.23") >= 0) { + if (fu_common_vercmp (self->ec_version, "00.00.00.23") >= 0) { g_debug ("using passive flow"); self->passive_flow = PASSIVE_REBOOT_MASK; fu_device_set_custom_flags (device, "skip-restart"); From 1d26689b2fa3c2ddf84024f1c218a8a3e0e1c56f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 30 Jan 2019 23:10:42 -0600 Subject: [PATCH 246/254] trivial: dell-dock: mirror update status from passive flow If fwupd is restarted multiple times before dock is unplugged, don't let any devices update if we can avoid it. --- plugins/dell-dock/dell-dock.quirk | 1 - plugins/dell-dock/fu-dell-dock-common.c | 17 +++++++++++++++++ plugins/dell-dock/fu-dell-dock-common.h | 2 ++ plugins/dell-dock/fu-dell-dock-i2c-mst.c | 3 ++- plugins/dell-dock/fu-dell-dock-i2c-tbt.c | 3 ++- plugins/dell-dock/fu-dell-dock-status.c | 2 ++ plugins/dell-dock/fu-plugin-dell-dock.c | 3 +++ 7 files changed, 28 insertions(+), 3 deletions(-) diff --git a/plugins/dell-dock/dell-dock.quirk b/plugins/dell-dock/dell-dock.quirk index 2bd2f23c9..ce0813c60 100644 --- a/plugins/dell-dock/dell-dock.quirk +++ b/plugins/dell-dock/dell-dock.quirk @@ -81,7 +81,6 @@ Name = Package level of Dell dock Summary = A representation of dock update status Plugin = dell_dock Vendor = Dell Inc -Flags = updatable FirmwareSizeMin = 24 FirmwareSizeMax = 24 InstallDuration = 5 diff --git a/plugins/dell-dock/fu-dell-dock-common.c b/plugins/dell-dock/fu-dell-dock-common.c index 6f4414d49..a3e0836f2 100644 --- a/plugins/dell-dock/fu-dell-dock-common.c +++ b/plugins/dell-dock/fu-dell-dock-common.c @@ -56,3 +56,20 @@ fu_dell_dock_will_replug (FuDevice *device) fu_device_set_remove_delay (device, timeout * 1000); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); } + +void +fu_dell_dock_clone_updatable (FuDevice *device) +{ + FuDevice *parent; + parent = fu_device_get_parent (device); + if (parent == NULL) + return; + if (fu_device_has_flag (parent, FWUPD_DEVICE_FLAG_UPDATABLE)) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + const gchar *message = fu_device_get_update_error (parent); + if (message != NULL) + fu_device_set_update_error (device, message); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } +} diff --git a/plugins/dell-dock/fu-dell-dock-common.h b/plugins/dell-dock/fu-dell-dock-common.h index d809b0d43..4be3c7733 100644 --- a/plugins/dell-dock/fu-dell-dock-common.h +++ b/plugins/dell-dock/fu-dell-dock-common.h @@ -35,4 +35,6 @@ gboolean fu_dell_dock_set_power (FuDevice *device, GError **error); void fu_dell_dock_will_replug (FuDevice *device); +void fu_dell_dock_clone_updatable (FuDevice *device); + #endif /* __FU_DELL_DOCK_COMMON_H */ diff --git a/plugins/dell-dock/fu-dell-dock-i2c-mst.c b/plugins/dell-dock/fu-dell-dock-i2c-mst.c index 5ceb848af..f564b7d6b 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-mst.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-mst.c @@ -906,13 +906,14 @@ fu_dell_dock_mst_setup (FuDevice *device, GError **error) if (version != NULL) fu_device_set_version (device, version); + fu_dell_dock_clone_updatable (device); + return TRUE; } static gboolean fu_dell_dock_mst_probe (FuDevice *device, GError **error) { - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_logical_id (FU_DEVICE (device), "mst"); return TRUE; diff --git a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c index 5d5b909c5..6d7c53736 100644 --- a/plugins/dell-dock/fu-dell-dock-i2c-tbt.c +++ b/plugins/dell-dock/fu-dell-dock-i2c-tbt.c @@ -203,7 +203,8 @@ fu_dell_dock_tbt_setup (FuDevice *device, GError **error) "Updates over I2C are disabled due to insufficient USB 3.1 G2 hub version"); return TRUE; } - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + + fu_dell_dock_clone_updatable (device); return TRUE; } diff --git a/plugins/dell-dock/fu-dell-dock-status.c b/plugins/dell-dock/fu-dell-dock-status.c index ff820236e..e28ee54b7 100644 --- a/plugins/dell-dock/fu-dell-dock-status.c +++ b/plugins/dell-dock/fu-dell-dock-status.c @@ -51,6 +51,8 @@ fu_dell_dock_status_setup (FuDevice *device, GError **error) fu_device_set_version (device, dynamic_version); fu_device_set_logical_id (FU_DEVICE (device), "status"); + fu_dell_dock_clone_updatable (device); + return TRUE; } diff --git a/plugins/dell-dock/fu-plugin-dell-dock.c b/plugins/dell-dock/fu-plugin-dell-dock.c index 9576f412b..4cda82707 100644 --- a/plugins/dell-dock/fu-plugin-dell-dock.c +++ b/plugins/dell-dock/fu-plugin-dell-dock.c @@ -117,6 +117,9 @@ fu_plugin_usb_device_added (FuPlugin *plugin, } } + /* clear updatable flag if parent doesn't have it */ + fu_dell_dock_clone_updatable (fu_device); + return TRUE; } From 7a3df4bb070e54ec8e3e998be6ad5a6a5f4e877e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 31 Jan 2019 10:27:22 -0600 Subject: [PATCH 247/254] fu-tool: Show UpdateMessage if applicable for install command When calling with a CAB as an install argument, this needs to be manually populated since the release won't be built. --- src/fu-device-private.h | 3 +++ src/fu-device.c | 18 ++++++++++++++++++ src/fu-main.c | 3 +++ src/fu-tool.c | 4 ++++ 4 files changed, 28 insertions(+) diff --git a/src/fu-device-private.h b/src/fu-device-private.h index 5eb5bf897..e4d30ca99 100644 --- a/src/fu-device-private.h +++ b/src/fu-device-private.h @@ -8,6 +8,7 @@ #define __FU_DEVICE_PRIVATE_H #include +#include G_BEGIN_DECLS @@ -26,6 +27,8 @@ void fu_device_set_alternate (FuDevice *self, FuDevice *alternate); gboolean fu_device_ensure_id (FuDevice *self, GError **error); +void fu_device_incorporate_from_component (FuDevice *device, + XbNode *component); G_END_DECLS diff --git a/src/fu-device.c b/src/fu-device.c index 1a30b9a56..e8c78c206 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -2089,6 +2089,24 @@ fu_device_incorporate (FuDevice *self, FuDevice *donor) klass->incorporate (self, donor); } +/** + * fu_device_incorporate_from_component: + * @self: A #FuDevice + * @component: A #XbNode + * + * Copy all properties from the donor AppStream component. + * + * Since: 1.2.4 + **/ +void +fu_device_incorporate_from_component (FuDevice *device, XbNode *component) +{ + const gchar *tmp; + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateMessage']", NULL); + if (tmp != NULL) + fwupd_device_set_update_message (FWUPD_DEVICE (device), tmp); +} + static void fu_device_class_init (FuDeviceClass *klass) { diff --git a/src/fu-main.c b/src/fu-main.c index 9c40f8484..7cbcc696c 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -629,6 +629,9 @@ fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) 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)) diff --git a/src/fu-tool.c b/src/fu-tool.c index cbb8dc1d8..dd61f575a 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -17,6 +17,7 @@ #include #include +#include "fu-device-private.h" #include "fu-engine.h" #include "fu-plugin-private.h" #include "fu-progressbar.h" @@ -823,6 +824,9 @@ fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) continue; } + /* if component should have an update message from CAB */ + fu_device_incorporate_from_component (device, component); + /* success */ g_ptr_array_add (install_tasks, g_steal_pointer (&task)); } From 303c4f0f902c37e58ba3a2328e80b3ab02e94c05 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 31 Jan 2019 14:46:04 -0600 Subject: [PATCH 248/254] trivial: upower: correct a logic error from ed021ab When unable to read battery value this should return FALSE to indicate AC power. --- plugins/upower/fu-plugin-upower.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/upower/fu-plugin-upower.c b/plugins/upower/fu-plugin-upower.c index 780cf34f5..3df98993f 100644 --- a/plugins/upower/fu-plugin-upower.c +++ b/plugins/upower/fu-plugin-upower.c @@ -108,7 +108,7 @@ fu_plugin_upower_check_on_battery (FuPlugin *plugin) value = g_dbus_proxy_get_cached_property (data->upower_proxy, "OnBattery"); if (value == NULL) { g_warning ("failed to get OnBattery value, assume on AC power"); - return TRUE; + return FALSE; } return g_variant_get_boolean (value); } From 9b31e6f33a84352e049dc4cdd1e6edd278f42718 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 31 Jan 2019 15:42:19 -0600 Subject: [PATCH 249/254] fu-progressbar: be more quiet when running non-interactive If fwupdmgr or fwupdtool are scripted all the erasing of lines and progressbars are much less useful. --- src/fu-progressbar.c | 17 +++++++++++++++++ src/fu-progressbar.h | 2 ++ src/fu-tool.c | 4 +++- src/fu-util.c | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/fu-progressbar.c b/src/fu-progressbar.c index 6dc0f36d9..eaf0009f4 100644 --- a/src/fu-progressbar.c +++ b/src/fu-progressbar.c @@ -29,6 +29,7 @@ struct _FuProgressbar gint64 last_animated; /* monotonic */ GTimer *time_elapsed; gdouble last_estimate; + gboolean interactive; }; G_DEFINE_TYPE (FuProgressbar, fu_progressbar, G_TYPE_OBJECT) @@ -271,6 +272,14 @@ fu_progressbar_update (FuProgressbar *self, FwupdStatus status, guint percentage if (status == FWUPD_STATUS_UNKNOWN) status = self->status; + if (!self->interactive) { + if (self->status != status) { + g_print ("%s\n", fu_progressbar_status_to_string (status)); + self->status = status; + } + return; + } + /* if the main loop isn't spinning and we've not had a chance to * execute the callback just do the refresh now manually */ if (percentage == 0 && @@ -302,6 +311,13 @@ fu_progressbar_update (FuProgressbar *self, FwupdStatus status, guint percentage self->percentage = percentage; } +void +fu_progressbar_set_interactive (FuProgressbar *self, gboolean interactive) +{ + g_return_if_fail (FU_IS_PROGRESSBAR (self)); + self->interactive = interactive; +} + void fu_progressbar_set_length_status (FuProgressbar *self, guint len) { @@ -332,6 +348,7 @@ fu_progressbar_init (FuProgressbar *self) self->length_status = 25; self->spinner_count_up = TRUE; self->time_elapsed = g_timer_new (); + self->interactive = TRUE; } static void diff --git a/src/fu-progressbar.h b/src/fu-progressbar.h index e48c35434..589b9f58b 100644 --- a/src/fu-progressbar.h +++ b/src/fu-progressbar.h @@ -26,6 +26,8 @@ void fu_progressbar_set_length_percentage (FuProgressbar *self, guint len); void fu_progressbar_set_title (FuProgressbar *self, const gchar *title); +void fu_progressbar_set_interactive (FuProgressbar *self, + gboolean interactive); G_END_DECLS diff --git a/src/fu-tool.c b/src/fu-tool.c index dd61f575a..f48b0ca5b 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1343,8 +1343,10 @@ main (int argc, char *argv[]) (GCompareFunc) fu_sort_command_name_cb); /* non-TTY consoles cannot answer questions */ - if (isatty (fileno (stdout)) == 0) + if (isatty (fileno (stdout)) == 0) { priv->no_reboot_check = TRUE; + fu_progressbar_set_interactive (priv->progressbar, FALSE); + } /* get a list of the commands */ priv->context = g_option_context_new (NULL); diff --git a/src/fu-util.c b/src/fu-util.c index 9ac788bac..a8427d0c6 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -2466,6 +2466,7 @@ main (int argc, char *argv[]) priv->no_unreported_check = TRUE; priv->no_metadata_check = TRUE; priv->no_reboot_check = TRUE; + fu_progressbar_set_interactive (priv->progressbar, FALSE); } /* get a list of the commands */ From 0de532b0b05db88dd617dc7e20c9f509d47f1206 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Sun, 20 Jan 2019 16:58:26 +0100 Subject: [PATCH 250/254] trivial: Allow iterating over the contents of an archive Signed-off-by: Richard Hughes --- src/fu-archive.c | 23 +++++++++++++++++++++++ src/fu-archive.h | 17 +++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/fu-archive.c b/src/fu-archive.c index c12d0b3cc..ac68a0ca7 100644 --- a/src/fu-archive.c +++ b/src/fu-archive.c @@ -79,6 +79,29 @@ fu_archive_lookup_by_fn (FuArchive *self, const gchar *fn, GError **error) return fw; } +/** + * fu_archive_iterate: + * @self: A #FuArchive + * @callback: A #FuArchiveIterateFunc. + * @user_data: User data. + * + * Iterates over the archive contents, calling the given function for each + * of the files found. + */ +void +fu_archive_iterate (FuArchive *self, FuArchiveIterateFunc callback, gpointer user_data) +{ + GHashTableIter iter; + gpointer key, value; + + g_return_if_fail (FU_IS_ARCHIVE (self)); + g_return_if_fail (callback != NULL); + + g_hash_table_iter_init (&iter, self->entries); + while (g_hash_table_iter_next (&iter, &key, &value)) + callback (self, (const gchar *)key, (GBytes *)value, user_data); +} + /* workaround the struct types of libarchive */ typedef struct archive _archive_read_ctx; diff --git a/src/fu-archive.h b/src/fu-archive.h index 1165ecd01..90a9db2a2 100644 --- a/src/fu-archive.h +++ b/src/fu-archive.h @@ -29,12 +29,29 @@ typedef enum { FU_ARCHIVE_FLAG_LAST } FuArchiveFlags; +/** + * FuArchiveIterateFunc: + * @self: A #FuArchive. + * @filename: A filename. + * @blob: The blob referenced by @filename. + * @user_data: User data. + * + * Specifies the type of archive iteration function. + */ +typedef void (*FuArchiveIterateFunc) (FuArchive *self, + const gchar *filename, + GBytes *bytes, + gpointer user_data); + FuArchive *fu_archive_new (GBytes *data, FuArchiveFlags flags, GError **error); GBytes *fu_archive_lookup_by_fn (FuArchive *self, const gchar *fn, GError **error); +void fu_archive_iterate (FuArchive *self, + FuArchiveIterateFunc callback, + gpointer user_data); G_END_DECLS From 0f0da353c2d3da46fe929c655ffdc1b5844b5ea1 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Fri, 1 Feb 2019 00:12:55 +0100 Subject: [PATCH 251/254] fastboot: Use a much longer timeout as the removal delay A device that has gone through a fastboot update may need more than the previous default of 10s to come back up. Just use a much longer value to make sure it's detected properly. Signed-off-by: Richard Hughes --- plugins/fastboot/fu-fastboot-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/fastboot/fu-fastboot-device.c b/plugins/fastboot/fu-fastboot-device.c index cd26d59bd..5cd541e08 100644 --- a/plugins/fastboot/fu-fastboot-device.c +++ b/plugins/fastboot/fu-fastboot-device.c @@ -13,6 +13,7 @@ #include "fu-chunk.h" #include "fu-fastboot-device.h" +#define FASTBOOT_REMOVE_DELAY_RE_ENUMERATE 60000 /* ms */ #define FASTBOOT_TRANSACTION_TIMEOUT 1000 /* ms */ #define FASTBOOT_TRANSACTION_RETRY_MAX 600 #define FASTBOOT_EP_IN 0x81 @@ -683,8 +684,7 @@ fu_fastboot_device_init (FuFastbootDevice *self) /* this is a safe default, even using USBv1 */ self->blocksz = 512; fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_set_remove_delay (FU_DEVICE (self), - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_set_remove_delay (FU_DEVICE (self), FASTBOOT_REMOVE_DELAY_RE_ENUMERATE); } static void From 0a26551bf3a0296fa0332e0a95876bf637e6342d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 1 Feb 2019 09:11:55 +0000 Subject: [PATCH 252/254] ata: Default to the non-activation 0xE subcommand During download and activation we have to reset the drive to apply the new firmware. If the kernel gets an unexpected ATA reset then it might panic. Default to activating the command on the next drive power-up to be safe. Many thanks to the Dell storage team for the advice. --- plugins/ata/fu-ata-device.c | 30 +++++++++++++++++++----------- plugins/ata/fu-self-test.c | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/plugins/ata/fu-ata-device.c b/plugins/ata/fu-ata-device.c index aaa2b7666..4210e00e2 100644 --- a/plugins/ata/fu-ata-device.c +++ b/plugins/ata/fu-ata-device.c @@ -38,6 +38,12 @@ struct ata_tf { #define ATA_OP_IDENTIFY 0xec #define ATA_OP_DOWNLOAD_MICROCODE 0x92 +#define ATA_SUBCMD_MICROCODE_OBSOLETE 0x01 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE 0x03 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK 0x07 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS 0x0e +#define ATA_SUBCMD_MICROCODE_ACTIVATE 0x0f + #define SG_CHECK_CONDITION 0x02 #define SG_DRIVER_SENSE 0x08 @@ -164,16 +170,13 @@ fu_ata_device_parse_id (FuAtaDevice *self, const guint8 *buf, gsize sz, GError * return FALSE; } - /* fallback to a sane default */ - if (self->transfer_mode == 0x0) { - if ((id[119] & 0x10) && (id[120] & 0x10)) - self->transfer_mode = 0x3; - else - self->transfer_mode = 0x7; - } + /* firmware will be applied when the device restarts */ + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); /* the newer, segmented transfer mode */ - if (self->transfer_mode == 0x3 || self->transfer_mode == 0xe) { + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE || + self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS) { xfer_min = id[234]; if (xfer_min == 0x0 || xfer_min == 0xffff) xfer_min = 1; @@ -485,7 +488,7 @@ fu_ata_device_write_firmware (FuDevice *device, GBytes *fw, GError **error) g_autoptr(GPtrArray) chunks = NULL; /* only one block allowed */ - if (self->transfer_mode == 0x7) + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK) max_size = 0xffff; /* check is valid */ @@ -537,7 +540,9 @@ fu_ata_device_set_quirk_kv (FuDevice *device, FuAtaDevice *self = FU_ATA_DEVICE (device); if (g_strcmp0 (key, "AtaTransferMode") == 0) { guint64 tmp = fu_common_strtoull (value); - if (tmp != 0x3 && tmp != 0x7 && tmp != 0xe) { + if (tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE && + tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS && + tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, @@ -571,9 +576,12 @@ fu_ata_device_set_quirk_kv (FuDevice *device, static void fu_ata_device_init (FuAtaDevice *self) { + /* we chose this default as _DOWNLOAD_CHUNKS_ACTIVATE applies the + * firmware straight away and the kernel might not like the unexpected + * ATA restart and panic */ + self->transfer_mode = ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS; fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_set_summary (FU_DEVICE (self), "ATA Drive"); fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); } diff --git a/plugins/ata/fu-self-test.c b/plugins/ata/fu-self-test.c index 805cf90a0..02aae8c2e 100644 --- a/plugins/ata/fu-self-test.c +++ b/plugins/ata/fu-self-test.c @@ -29,7 +29,7 @@ fu_ata_id_func (void) dev = fu_ata_device_new_from_blob ((guint8 *)data, sz, &error); g_assert_no_error (error); g_assert_nonnull (dev); - g_assert_cmpint (fu_ata_device_get_transfer_mode (dev), ==, 0x3); + g_assert_cmpint (fu_ata_device_get_transfer_mode (dev), ==, 0xe); g_assert_cmpint (fu_ata_device_get_transfer_blocks (dev), ==, 0x1); g_assert_cmpstr (fu_device_get_serial (FU_DEVICE (dev)), ==, "A45A078A198600476509"); g_assert_cmpstr (fu_device_get_name (FU_DEVICE (dev)), ==, "SATA SSD"); From 7ccba7afba9fbd35179f4975f7fa20e0eb319ea3 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 1 Feb 2019 14:25:02 +0000 Subject: [PATCH 253/254] Remove the autogenerated headers in the gettext files These change every release as we're importing from Transifex. They're not required, so strip them out using a small python script. --- RELEASE | 4 +-- contrib/fix_translations.py | 50 +++++++++++++++++++++++++++++++++++++ po/ast.po | 3 --- po/ca.po | 3 --- po/cs.po | 3 --- po/de.po | 3 --- po/en_GB.po | 3 --- po/eu.po | 3 --- po/fi.po | 3 --- po/fr.po | 3 --- po/fur.po | 3 --- po/he.po | 3 --- po/hi.po | 3 --- po/hr.po | 3 --- po/hu.po | 3 --- po/id.po | 3 --- po/it.po | 3 --- po/kk.po | 3 --- po/ko.po | 3 --- po/ky.po | 3 --- po/nl.po | 3 --- po/oc.po | 3 --- po/pl.po | 3 --- po/pt_BR.po | 3 --- po/ru.po | 3 --- po/sk.po | 3 --- po/sr.po | 3 --- po/sv.po | 3 --- po/tr.po | 3 --- po/uk.po | 3 --- po/zh_CN.po | 3 --- po/zh_TW.po | 3 --- 32 files changed, 51 insertions(+), 93 deletions(-) create mode 100755 contrib/fix_translations.py diff --git a/RELEASE b/RELEASE index 1ebc3c19c..302564983 100644 --- a/RELEASE +++ b/RELEASE @@ -11,9 +11,7 @@ Update translations: ninja-build fwupd-pot tx push --source tx pull --all --force --minimum-perc=5 -for f in ../po/*.po; do -msgattrib --no-location --translated --no-wrap --sort-output $f --output-file=$f -done +../contrib/fix_translations.py ../po git add ../po/*.po 2. Commit changes to git: diff --git a/contrib/fix_translations.py b/contrib/fix_translations.py new file mode 100755 index 000000000..8014fb11d --- /dev/null +++ b/contrib/fix_translations.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1+ + +import sys +import os +import subprocess + +def _do_msgattrib(fn): + argv = ['msgattrib', + '--no-location', + '--translated', + '--no-wrap', + '--sort-output', + fn, + '--output-file=' + fn] + ret = subprocess.run(argv) + if ret.returncode != 0: + return + +def _do_nukeheader(fn): + clean_lines = [] + with open(fn) as f: + lines = f.readlines() + for line in lines: + if line.startswith('"POT-Creation-Date:'): + continue + if line.startswith('"PO-Revision-Date:'): + continue + if line.startswith('"Last-Translator:'): + continue + clean_lines.append(line) + with open(fn, 'w') as f: + f.writelines(clean_lines) + +def _process_file(fn): + _do_msgattrib(fn) + _do_nukeheader(fn) + +if __name__ == '__main__': + if len(sys.argv) == 1: + print('path required') + sys.exit(1) + try: + dirname = sys.argv[1] + for fn in os.listdir(dirname): + if fn.endswith('.po'): + _process_file(os.path.join(dirname, fn)) + except NotADirectoryError as _: + print('path required') + sys.exit(2) diff --git a/po/ast.po b/po/ast.po index d9e6b2f35..c9181d05c 100644 --- a/po/ast.po +++ b/po/ast.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Asturian (http://www.transifex.com/freedesktop/fwupd/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/ca.po b/po/ca.po index ce33c478b..d3db4d2cb 100644 --- a/po/ca.po +++ b/po/ca.po @@ -9,9 +9,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-29 15:25+0000\n" -"Last-Translator: Antoni Bella Pérez \n" "Language-Team: Catalan (http://www.transifex.com/freedesktop/fwupd/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/cs.po b/po/cs.po index 7a25ec226..7182585cf 100644 --- a/po/cs.po +++ b/po/cs.po @@ -10,9 +10,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Czech (http://www.transifex.com/freedesktop/fwupd/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/de.po b/po/de.po index 9841a1c86..5caa173b4 100644 --- a/po/de.po +++ b/po/de.po @@ -10,9 +10,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: German (http://www.transifex.com/freedesktop/fwupd/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/en_GB.po b/po/en_GB.po index a29d59e3a..2f1e41160 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/freedesktop/fwupd/language/en_GB/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/eu.po b/po/eu.po index 685a0c25b..5614fddec 100644 --- a/po/eu.po +++ b/po/eu.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-06 14:54+0100\n" -"PO-Revision-Date: 2018-06-06 14:00+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Basque (http://www.transifex.com/freedesktop/fwupd/language/eu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/fi.po b/po/fi.po index da403fca1..6cd7645c1 100644 --- a/po/fi.po +++ b/po/fi.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Finnish (http://www.transifex.com/freedesktop/fwupd/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/fr.po b/po/fr.po index 5650849dd..21026afb2 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: French (http://www.transifex.com/freedesktop/fwupd/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/fur.po b/po/fur.po index cfff7927a..ac75c9c9a 100644 --- a/po/fur.po +++ b/po/fur.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Friulian (http://www.transifex.com/freedesktop/fwupd/language/fur/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/he.po b/po/he.po index 8b2a58924..e3fff2455 100644 --- a/po/he.po +++ b/po/he.po @@ -9,9 +9,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hebrew (http://www.transifex.com/freedesktop/fwupd/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/hi.po b/po/hi.po index abdad4ffd..6cb53320c 100644 --- a/po/hi.po +++ b/po/hi.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hindi (http://www.transifex.com/freedesktop/fwupd/language/hi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/hr.po b/po/hr.po index 7dc5b42ec..a458c451e 100644 --- a/po/hr.po +++ b/po/hr.po @@ -10,9 +10,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Croatian (http://www.transifex.com/freedesktop/fwupd/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/hu.po b/po/hu.po index c2fd3858d..9e337f677 100644 --- a/po/hu.po +++ b/po/hu.po @@ -11,9 +11,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-12-16 19:43+0000\n" -"Last-Translator: Balázs Meskó \n" "Language-Team: Hungarian (http://www.transifex.com/freedesktop/fwupd/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/id.po b/po/id.po index dff70f4fb..0ded94995 100644 --- a/po/id.po +++ b/po/id.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Indonesian (http://www.transifex.com/freedesktop/fwupd/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/it.po b/po/it.po index 3824307ff..381a9d650 100644 --- a/po/it.po +++ b/po/it.po @@ -9,9 +9,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Italian (http://www.transifex.com/freedesktop/fwupd/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/kk.po b/po/kk.po index 6fa7e2e9c..799aa994b 100644 --- a/po/kk.po +++ b/po/kk.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-09-01 14:26+0100\n" -"PO-Revision-Date: 2017-09-01 13:27+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Kazakh (http://www.transifex.com/freedesktop/fwupd/language/kk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/ko.po b/po/ko.po index 61e1c78c6..5420d692d 100644 --- a/po/ko.po +++ b/po/ko.po @@ -9,9 +9,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Korean (http://www.transifex.com/freedesktop/fwupd/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/ky.po b/po/ky.po index 742e6ae91..f8ed34ec2 100644 --- a/po/ky.po +++ b/po/ky.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-07 11:16+0000\n" -"PO-Revision-Date: 2018-10-12 11:10+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Kyrgyz (http://www.transifex.com/freedesktop/fwupd/language/ky/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/nl.po b/po/nl.po index bd18d686c..c8b395ce8 100644 --- a/po/nl.po +++ b/po/nl.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Dutch (http://www.transifex.com/freedesktop/fwupd/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/oc.po b/po/oc.po index de4a1215a..21d8bd97b 100644 --- a/po/oc.po +++ b/po/oc.po @@ -9,9 +9,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Occitan (post 1500) (http://www.transifex.com/freedesktop/fwupd/language/oc/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/pl.po b/po/pl.po index fb81b1c93..3f53b1e63 100644 --- a/po/pl.po +++ b/po/pl.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Polish (http://www.transifex.com/freedesktop/fwupd/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/pt_BR.po b/po/pt_BR.po index ffa3dc9f3..ba6499db4 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -12,9 +12,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-12-05 22:10+0000\n" -"Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/freedesktop/fwupd/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/ru.po b/po/ru.po index 01986bab5..631c93f8e 100644 --- a/po/ru.po +++ b/po/ru.po @@ -9,9 +9,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Russian (http://www.transifex.com/freedesktop/fwupd/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/sk.po b/po/sk.po index 4f55f8a8f..fa403fdaf 100644 --- a/po/sk.po +++ b/po/sk.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Slovak (http://www.transifex.com/freedesktop/fwupd/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/sr.po b/po/sr.po index c7029da15..8c8b4bf7c 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,9 +10,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Serbian (http://www.transifex.com/freedesktop/fwupd/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/sv.po b/po/sv.po index ca08776a8..84f5bc842 100644 --- a/po/sv.po +++ b/po/sv.po @@ -12,9 +12,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Swedish (http://www.transifex.com/freedesktop/fwupd/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/tr.po b/po/tr.po index 044d46eac..41770aaf0 100644 --- a/po/tr.po +++ b/po/tr.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Turkish (http://www.transifex.com/freedesktop/fwupd/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/uk.po b/po/uk.po index 7a9702415..27f7c6f70 100644 --- a/po/uk.po +++ b/po/uk.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Ukrainian (http://www.transifex.com/freedesktop/fwupd/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/zh_CN.po b/po/zh_CN.po index cb57be863..c7c75f45b 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -12,9 +12,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Chinese (China) (http://www.transifex.com/freedesktop/fwupd/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/po/zh_TW.po b/po/zh_TW.po index 913feef26..52f8b62fc 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -8,9 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-30 15:16+0000\n" -"PO-Revision-Date: 2018-11-28 13:44+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/freedesktop/fwupd/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 8ece8874b5588f74805ba1ee283af295d2a276d6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 1 Feb 2019 14:27:32 +0000 Subject: [PATCH 254/254] Release fwupd 1.2.4 --- data/org.freedesktop.fwupd.metainfo.xml | 32 ++ po/LINGUAS | 1 + po/af.po | 417 ++++++++++++++++++++++++ po/ca.po | 12 +- po/cs.po | 12 +- po/de.po | 12 +- po/fur.po | 2 +- po/hr.po | 2 +- po/hu.po | 12 +- po/id.po | 2 +- po/it.po | 26 +- po/ko.po | 2 +- po/pl.po | 26 +- po/pt_BR.po | 12 +- po/sr.po | 2 +- po/sv.po | 207 +++++++++++- po/uk.po | 26 +- po/zh_CN.po | 2 +- po/zh_TW.po | 12 +- 19 files changed, 707 insertions(+), 112 deletions(-) create mode 100644 po/af.po diff --git a/data/org.freedesktop.fwupd.metainfo.xml b/data/org.freedesktop.fwupd.metainfo.xml index 69241135d..bd99fe790 100644 --- a/data/org.freedesktop.fwupd.metainfo.xml +++ b/data/org.freedesktop.fwupd.metainfo.xml @@ -31,6 +31,38 @@ moderate + + +

        This release adds the following features:

        +
          +
        • Add a directory remote that generates metadata
        • +
        • Add a new remote type "directory"
        • +
        • Add a plugin to update Wacom embedded EMR and AES panels
        • +
        • Add a plugin to upgrade firmware on ATA-ATAPI hardware
        • +
        • Add a quirk to use the legacy bootmgr description
        • +
        • Add flag to support manually aligning the NVMe firmware to the FWUG value
        • +
        • Add SuperIO IT89xx device support
        • +
        • Add support for Dell dock passive flow
        • +
        • Add 'update' and 'get-updates' commands to fwupdtool
        • +
        • Allow Dell dock flashing Thunderbolt over I2C
        • +
        • Check the battery percentage before flashing
        • +
        • Show a per-release source and details URL
        • +
        • Show a `UpdateMessage` and display it in tools
        • +
        +

        This release fixes the following bugs:

        +
          +
        • Add the needs-shutdown quirk to Phison NVMe drives
        • +
        • Correct Nitrokey Storage invalid firmware version read
        • +
        • Do not check the BGRT status before uploading a UX capsule
        • +
        • Do the UEFI UX checksum calculation in fwupd
        • +
        • Fix flashing various Jabra devices
        • +
        • Fix the parser to support extended segment addresses
        • +
        • Flash the fastboot partition after downloading the file
        • +
        • Show a console warning if loading an out-of-tree plugin
        • +
        • Support FGUID to get the SKU GUID for NVMe hardware
        • +
        +
        +

        This release fixes the following bug:

        diff --git a/po/LINGUAS b/po/LINGUAS index c96395e31..0c8caf910 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -1,3 +1,4 @@ +af ast ca cs diff --git a/po/af.po b/po/af.po new file mode 100644 index 000000000..dea9889d0 --- /dev/null +++ b/po/af.po @@ -0,0 +1,417 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# F Wolff , 2019 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Afrikaans (http://www.transifex.com/freedesktop/fwupd/language/af/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: af\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuut oor" +msgstr[1] "%.0f minute oor" + +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dag" +msgstr[1] "%u dae" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u uur" +msgstr[1] "%u ure" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuut" +msgstr[1] "%u minute" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekonde" +msgstr[1] "%u sekondes" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Bygevoeg" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Ouderdom" + +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "’n Bywerking vereis dat die stelsel herbegin om te voltooi." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Antwoord ja op alle vrae" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribute" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Kanselleer" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Gekanselleer" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Verander" + +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrolesom" + +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Vlokkie-ID" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Kies 'n toestel:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Kies 'n vrystelling:" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Opdrag nie gevind nie" + +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Pak tans uit…" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Beskrywing" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Toestel bygevoeg:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Toestel verander:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Toestel verwyder:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Toestelle wat suksesvol bygewerk is:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Toestelle wat nie korrek bygewerk is nie:" + +msgid "Done!" +msgstr "Klaar!" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Gradeer tans %s af vanaf %s na %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Gradeer tans %s af…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Laai tans af…" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Geaktiveer" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Vee tans uit…" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Kon nie aflaai nie a.g.v. bedienerlimiet" + +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Kry tans lêer" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Kry tans metadata" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Kry tans handtekening" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Lêernaam" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Lêernaamhandtekening" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Gevind" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Ledig…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installeer tans op %s…" + +msgid "Keyring" +msgstr "Sleutelring" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Minder as een minuut oor" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Laai tans…" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadata-URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadata-URI-handtekening" + +msgid "Mode" +msgstr "Modus" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Naam" + +msgid "OK" +msgstr "Goed" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Wagwoord" + +msgid "Permission denied" +msgstr "Toestemming gewyer" + +msgid "Print the version number" +msgstr "Druk die weergawenommer" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioriteit" + +msgid "Proceed with upload?" +msgstr "Gaan voort met oplaai?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lees tans…" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Streek" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Herinstalleer tans %s met %s… " + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Verwyder" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Internetverbinding is nodig" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Herbegin nou?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Herbegin tans toestel…" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Skeduleer die installasie vir die volgende herbegin indien moontlik" + +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Skeduleer tans…" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Reeksnommer" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Wys toestelle wat nie bygewerk kan word nie" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Toestand" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Opsomming" + +msgid "Target" +msgstr "Teiken" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Oordraggrootte" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipe" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Onbekend" + +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Bywerking se kontrolesom" + +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Bywerking se beskrywing" + +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Bywerking se duur" + +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Bywerking se ligging" + +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Bywerking se naam" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Bywerking se opsomming" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Bywerking se weergawe" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Werk nou by?" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Werk tans %s by vanaf %s na %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Werk tans %s by…" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Oplaaiboodskap:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Laai verslag nou op?" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Gebruikernaam" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verifieer tans…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Weergawe" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Wag tans…" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Skryf tans…" diff --git a/po/ca.po b/po/ca.po index d3db4d2cb..3dfb1bb73 100644 --- a/po/ca.po +++ b/po/ca.po @@ -81,7 +81,7 @@ msgstr "Permet tornar a la versió anterior del microprogramari" msgid "Allow re-installing existing firmware versions" msgstr "Permet tornar a instal·lar les versions de microprogramari existents" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Una actualització requereix un reinici per a completar-se." @@ -509,12 +509,6 @@ msgstr "Instal·la microprogramari sense signar per al dispositiu" msgid "Install unsigned system firmware" msgstr "Instal·la microprogramari sense signar per al sistema" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "S'està instal·lant %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "S'està instal·lant l'actualització de microprogramari..." @@ -846,10 +840,6 @@ msgstr "Objectiu" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "El LVFS és un servei gratuït que funciona com una entitat legal independent i no té cap vincle amb la $OS_RELEASE:NAME$. És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats. Tot el microprogramari només és proporcionat pel fabricant original dels equips." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "L'actualització requereix un reinici per a completar-se." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Aquest programa només pot funcionar correctament com a «root»" diff --git a/po/cs.po b/po/cs.po index 7182585cf..d8e467eac 100644 --- a/po/cs.po +++ b/po/cs.po @@ -56,7 +56,7 @@ msgstr "Povolit přechod na nižší verze firmwaru" msgid "Allow re-installing existing firmware versions" msgstr "Povolit reinstalaci stávající verze firmwaru" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Některá z aktualizací vyžaduje pro dokončení restart." @@ -478,12 +478,6 @@ msgstr "Instalace nepodepsaného firmwaru zařízení" msgid "Install unsigned system firmware" msgstr "Instalace nepodepsaného systémového firmwaru" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Instaluje se zařízení %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instaluje se aktualizace firmwaru…" @@ -799,10 +793,6 @@ msgstr "Cíl" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Pro dokončení aktualizace je potřeba provést restart." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Tento program může správně fungovat jen pod uživatelem root" diff --git a/po/de.po b/po/de.po index 5caa173b4..6c59a74d3 100644 --- a/po/de.po +++ b/po/de.po @@ -50,7 +50,7 @@ msgstr "Herabstufung von Firmware-Versionen zulassen" msgid "Allow re-installing existing firmware versions" msgstr "Erneute Installation vorhandener Firmware-Versionen erlauben" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Ein Neustart ist erforderlich, um eine Aktualisierung abzuschließen." @@ -434,12 +434,6 @@ msgstr "Nicht-signierte Geräte-Firmware installieren" msgid "Install unsigned system firmware" msgstr "Nicht-signierte System-Firmware installieren" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "%s wird installiert" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Firmware-Aktualisierung wird installiert …" @@ -741,10 +735,6 @@ msgstr "Ziel" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "Der LVFS ist ein kostenloser Dienst, der als unabhängige juristische Person arbeitet und keine Verbindung zu $OS_RELEASE:NAME$ hat. Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft. Die gesamte Firmware wird nur vom Originalhersteller zur Verfügung gestellt." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Ein Neustart ist erforderlich, um die Aktualisierung abzuschließen." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Dieses Programm funktioniert möglicherweise nur als root korrekt" diff --git a/po/fur.po b/po/fur.po index ac75c9c9a..489c19207 100644 --- a/po/fur.po +++ b/po/fur.po @@ -41,7 +41,7 @@ msgstr "Permet di tornâ indaûr aes versions di firmware precedentis" msgid "Allow re-installing existing firmware versions" msgstr "Permet di tornâ a instalâ lis versions dai firmware esistentis" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Un inzornament al à bisugne che si torni a inviâ il computer par finî." diff --git a/po/hr.po b/po/hr.po index a458c451e..d4f773c99 100644 --- a/po/hr.po +++ b/po/hr.po @@ -43,7 +43,7 @@ msgstr "Dopusti vraćanje starije inačice frimvera" msgid "Allow re-installing existing firmware versions" msgstr "Dopusti ponovnu instalaciju frimvera postojeće inačice" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Nadopuna zahtijeva ponovno pokretanje za završetak." diff --git a/po/hu.po b/po/hu.po index 9e337f677..5d8b4dccf 100644 --- a/po/hu.po +++ b/po/hu.po @@ -83,7 +83,7 @@ msgstr "Firmware verziók visszafejlesztésének engedélyezése" msgid "Allow re-installing existing firmware versions" msgstr "Meglévő firmware verziók újratelepítésének engedélyezése" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Egy frissítés újraindítást igényel a befejezéshez." @@ -511,12 +511,6 @@ msgstr "Nem aláírt eszköz firmware telepítése" msgid "Install unsigned system firmware" msgstr "Nem aláírt rendszer firmware telepítése" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "%s telepítése" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Firmware frissítés telepítése…" @@ -848,10 +842,6 @@ msgstr "Cél" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "Az LVFS egy ingyenes szolgáltatás, amely független jogi entitásként működik, és nincs kapcsolata a $OS_RELEASE:NAME$ operációs rendszerrel. A disztribúció szállítója nem biztos, hogy ellenőrízte kompatibilitási szempontból a firmware frissítést. Mindent firmware-t csak az eredeti termék gyártója biztosít." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "A frissítés befejezéséhez újraindítás szükséges." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Ez a program jelenleg lehet, hogy csak rendszergazdaként működik" diff --git a/po/id.po b/po/id.po index 0ded94995..93058cb8e 100644 --- a/po/id.po +++ b/po/id.po @@ -41,7 +41,7 @@ msgstr "Izinkan penuruntingkatan versi firmware" msgid "Allow re-installing existing firmware versions" msgstr "Izinkan pemasangan ulang versi firmware yang telah ada" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Suatu pembaruan memerlukan boot ulang agar lengkap." diff --git a/po/it.po b/po/it.po index 381a9d650..f7e407f3a 100644 --- a/po/it.po +++ b/po/it.po @@ -4,7 +4,7 @@ # # Translators: # Gianvito Cavasoli , 2016 -# Milo Casagrande , 2017-2018 +# Milo Casagrande , 2017-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -81,10 +81,14 @@ msgstr "Consente di tornare alle precedenti versioni del firmware" msgid "Allow re-installing existing firmware versions" msgstr "Consente di reinstallare versioni del firmware esistenti" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Per essere completato, un aggiornamento richiede un riavvio." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Per essere completato, un aggiornamento richiede lo spegnimento del sistema." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Risponde affermativamente a tutte le domande" @@ -509,12 +513,6 @@ msgstr "Installa firmware non firmato del dispositivo" msgid "Install unsigned system firmware" msgstr "Installa firmware non firmato di sistema" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Installazione di %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Installazione aggiornamento firmware…" @@ -819,6 +817,10 @@ msgstr "Mostra debug dell'ultimo tentativo di aggiornamento" msgid "Show the information of firmware update status" msgstr "Mostra informazioni sullo stato degli aggiornamenti firmware" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Spegnere ora?" + msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Specifica vendor/ID prodotto di un dispositivo DFU" @@ -846,10 +848,6 @@ msgstr "Obiettivo" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente e non ha alcun legame con $OS_RELEASE:NAME$. Il distributore potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o con i propri dispositivi collegati. Il firmware viene fornito solamente dall'OEM." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Per essere completato, l'aggiornamento richiede un riavvio." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Questo programma può funzionare correttamente solo come utente root" @@ -925,6 +923,10 @@ msgstr "Riepilogo aggiornameto" msgid "Update Version" msgstr "Versione aggiornamento" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Aggiorna tutti i dispositivi corrispondenti ai metadati locali" + #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Questo è un problema noto, consultare il seguente URL per maggiori informazioni:" diff --git a/po/ko.po b/po/ko.po index 5420d692d..6fbb5e481 100644 --- a/po/ko.po +++ b/po/ko.po @@ -46,7 +46,7 @@ msgstr "펌웨어 다운그레이드를 허용합니다" msgid "Allow re-installing existing firmware versions" msgstr "기존 펌웨어 버전 재설치를 허용합니다" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "업데이트를 완료하려면 다시 시작해야 합니다." diff --git a/po/pl.po b/po/pl.po index 3f53b1e63..e53649f2c 100644 --- a/po/pl.po +++ b/po/pl.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Piotr Drąg , 2015-2018 +# Piotr Drąg , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -90,10 +90,14 @@ msgstr "Umożliwia instalowanie poprzednich wersji oprogramowania sprzętowego" msgid "Allow re-installing existing firmware versions" msgstr "Umożliwia ponowne instalowanie istniejących wersji oprogramowania sprzętowego" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Ukończenie aktualizacji wymaga wyłączenia komputera." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Odpowiada tak na wszystkie pytania" @@ -520,12 +524,6 @@ msgstr "Instalacja niepodpisanego oprogramowania sprzętowego urządzenia" msgid "Install unsigned system firmware" msgstr "Instalacja niepodpisanego oprogramowania sprzętowego komputera" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Instalowanie urządzenia %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instalowanie aktualizacji oprogramowania sprzętowego…" @@ -830,6 +828,10 @@ msgstr "Wyświetla dziennik debugowania z ostatniej aktualizacji" msgid "Show the information of firmware update status" msgstr "Wyświetla informacje o stanie aktualizacji oprogramowania sprzętowego" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Wyłączyć teraz?" + msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Podaje identyfikatory dostawcy/produktu urządzenia DFU" @@ -857,10 +859,6 @@ msgstr "Cel" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS to wolny serwis działający jako niezależny podmiot prawny niemający związków z systemem $OS_RELEASE:NAME$. Dystrybutor używanego systemu mógł nie zweryfikować żadnych aktualizacji oprogramowania sprzętowego pod kątem zgodności z używanym komputerem lub podłączonymi urządzeniami. Każde oprogramowanie sprzętowe jest dostarczane wyłącznie przez oryginalnego producenta sprzętu." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Ten program może działać poprawnie tylko jako root" @@ -936,6 +934,10 @@ msgstr "Podsumowanie aktualizacji" msgid "Update Version" msgstr "Wersja aktualizacji" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Aktualizuje wszystkie urządzenia pasujące do lokalnych metadanych" + #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Niepowodzenie aktualizacji to znany problem, pod tym adresem dostępnych jest więcej informacji:" diff --git a/po/pt_BR.po b/po/pt_BR.po index ba6499db4..7339bdc18 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -84,7 +84,7 @@ msgstr "Permite fazer downgrade de versões de firmware" msgid "Allow re-installing existing firmware versions" msgstr "Permite reinstalar versões existentes de firmware" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Uma atualização requer uma reinicialização para completar." @@ -512,12 +512,6 @@ msgstr "Instalar firmware não assinado no dispositivo" msgid "Install unsigned system firmware" msgstr "Instalar firmware não assinado no sistema" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Instalando %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Instalando atualização de firmware…" @@ -849,10 +843,6 @@ msgstr "Alvo" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "O LVFS é um serviço livre que opera como uma entidade legal independente e tem nenhuma conexão com $OS_RELEASE:NAME$. Seu distribuidor pode não ter verificado alguma das atualizações de firmware por compatibilidade com seu sistema ou dispositivos conectados. Todos os firmwares são fornecidos apenas pelo fabricante do equipamento original." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "A atualização requer uma reinicialização para completar." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Esse programa só pode funcionar corretamente como root" diff --git a/po/sr.po b/po/sr.po index 8c8b4bf7c..8c5d1e6bb 100644 --- a/po/sr.po +++ b/po/sr.po @@ -43,7 +43,7 @@ msgstr "Дозволи уназађивање издања фирмвера" msgid "Allow re-installing existing firmware versions" msgstr "Дозволи поновно инсталирање већ постојећих издања фирмвера" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Потребно је поново покретање да би се исправка применила." diff --git a/po/sv.po b/po/sv.po index 84f5bc842..de6d84139 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Anders Jonsson , 2017 +# Anders Jonsson , 2017,2019 # Andreas Henriksson , 2017 # Josef Andersson , 2015,2017-2018 # Josef Andersson , 2015,2017 @@ -19,11 +19,46 @@ msgstr "" "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0fminut kvarstår" +msgstr[1] "%.0f minuter kvarstår" + #. TRANSLATORS: first replacement is device name #, c-format msgid "%s has firmware updates:" msgstr "%s har uppdateringar för fast programvara:" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dag" +msgstr[1] "%u dagar" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u timme" +msgstr[1] "%u timmar" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%uminut" +msgstr[1] "%u minuter" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekund" +msgstr[1] "%u sekunder" + #. TRANSLATORS: this is when a device is hotplugged msgid "Added" msgstr "Tillagd" @@ -49,7 +84,7 @@ msgstr "Tillåt att nedgradera versioner av fast programvara" msgid "Allow re-installing existing firmware versions" msgstr "Tillåt att installera om befintliga versioner av fast programvara" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "En uppdatering kräver en omstart för att färdigställas." @@ -61,10 +96,18 @@ msgstr "Svara ja på alla frågor" msgid "Apply a binary patch" msgstr "Applicera en binär lagning" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Tillämpa uppdateringar för fast programvara" + #. TRANSLATORS: command description msgid "Attach DFU capable device back to runtime" msgstr "Anslut DFU-kapabel enhet till körtid" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Fäst till fast programvaruläge" + #. TRANSLATORS: device attributes, i.e. things that #. * the device can do msgid "Attributes" @@ -187,6 +230,10 @@ msgstr "Beskrivning" msgid "Detach currently attached DFU capable device" msgstr "Koppla från anslutna DFU-kapabla enheter" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Koppla från till starthanterarläge" + #. TRANSLATORS: this is when a device is hotplugged msgid "Device added:" msgstr "Enhet tillagd:" @@ -207,10 +254,17 @@ msgstr "Enheter som har uppdaterats:" msgid "Devices that were not updated correctly:" msgstr "Enheter som inte uppdaterades korrekt:" +msgid "Disabled fwupdate debugging" +msgstr "Inaktiverade fwupdate-felsökning" + #. TRANSLATORS: command description msgid "Disables a given remote" msgstr "Inaktiverar en given fjärr." +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Visa version" + #. TRANSLATORS: command line option msgid "Do not check for old metadata" msgstr "Kontrollera inte gammal metadata" @@ -223,6 +277,10 @@ msgstr "Kontrollera inte om det krävs omstart efter uppdatering" msgid "Do not check for unreported history" msgstr "Kontrollera inte ej rapporterad historik" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Skriv inte till historikdatabasen" + msgid "Done!" msgstr "Klar!" @@ -237,6 +295,11 @@ msgstr "Nergradera fast programvara på en enhet" msgid "Downgrading %s from %s to %s... " msgstr "Nedgraderar %s från %s till %s… " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Nedgraderar %s…" + #. TRANSLATORS: downloading from a remote server msgid "Downloading…" msgstr "Laddar ner..." @@ -253,6 +316,14 @@ msgstr "Skriv ut detaljer om fast programvarufil" msgid "Dump information about a binary patch to the screen" msgstr "Dumpa informationen om en binär lagning till skärmen" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Angiven ESP var inte giltig" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Aktivera stöd för uppdatering av fast programvara på system som stöds" + #. TRANSLATORS: Turn on the remote msgid "Enable this remote?" msgstr "Aktivera denna fjärr?" @@ -261,10 +332,16 @@ msgstr "Aktivera denna fjärr?" msgid "Enabled" msgstr "Aktiverad" +msgid "Enabled fwupdate debugging" +msgstr "Aktiverade fwupdate-felsökning" + #. TRANSLATORS: command description msgid "Enables a given remote" msgstr "Aktiverar en given fjärr." +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Att aktivera denna funktionalitet görs på egen risk, vilket betyder att du måste kontakta den ursprungliga tillverkaren av din utrustning om problem som orsakas av dessa uppdateringar. Endast problem med själva uppdateringsprocessen ska rapporteras på $OS_RELEASE:BUG_REPORT_URL$." + #. TRANSLATORS: show the user a warning msgid "Enabling this remote is done at your own risk." msgstr "Att aktivera denna fjärr görs på egen risk." @@ -289,6 +366,10 @@ msgstr "Avsluta efter en kort fördröjning" msgid "Exit after the engine has loaded" msgstr "Avsluta efter att motorn har lästs in" +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Misslyckades med hämtning på grund av servergräns" + #. TRANSLATORS: quirks are device-specific workarounds msgid "Failed to load quirks" msgstr "Misslyckades med att läsa in speciallösning" @@ -344,6 +425,15 @@ msgid_plural "Firmware metadata has not been updated for %u days and may not be msgstr[0] "Metadata för fast programvara har inte uppdaterats på %udag och kan vara utdaterad." msgstr[1] "Metadata för fast programvara har inte uppdaterats på %udagar och kan vara utdaterad." +msgid "Firmware updates are not supported on this machine." +msgstr "Uppdateringar av fast programvara stöds inte på denna maskin." + +msgid "Firmware updates are supported on this machine." +msgstr "Uppdateringar av fast programvara stöds på denna maskin." + +msgid "Force the action ignoring all warnings" +msgstr "Tvinga åtgärden, ignorera alla varningar" + #. TRANSLATORS: detected a DFU device msgid "Found" msgstr "Hittad" @@ -351,10 +441,18 @@ msgstr "Hittad" msgid "GUID" msgstr "GUID" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Hämta alla enheter enligt systemets topologi" + #. TRANSLATORS: command description msgid "Get all devices that support firmware updates" msgstr "Hämta alla enheter som stödjer uppdateringar av fast programvara" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Erhåll alla aktiverade insticksmoduler som är registrerade i systemet" + #. TRANSLATORS: command description msgid "Gets details about a firmware file" msgstr "Hämtar detaljer om en fast programvarufil" @@ -387,6 +485,10 @@ msgstr "ID" msgid "Idle…" msgstr "Väntar…" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Installera en fast programvaru-blob på en enhet" + #. TRANSLATORS: command description msgid "Install a firmware file on this hardware" msgstr "Installera en fast programvarufil på denna hårdvara" @@ -414,9 +516,18 @@ msgstr "Installera osignerad fast programvara för systemet" msgid "Installing firmware update…" msgstr "Installerar uppdatering för fast programvara…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installerar på %s…" + msgid "Keyring" msgstr "Nyckelring" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Mindre än en minut kvarstår" + msgid "Linux Vendor Firmware Service (stable firmware)" msgstr "Linux Vendor Firmware Service (stabil fastprogramvara)" @@ -427,10 +538,18 @@ msgstr "Linux Vendor Firmware Service (fastprogramvara för testning)" msgid "List currently attached DFU capable devices" msgstr "Lista aktuella anslutna DFU-kapabla enheter" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Lista uppdateringar för fast programvara som stöds" + #. TRANSLATORS: parsing the firmware information msgid "Loading…" msgstr "Läser in…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Vitlista manuellt specifika insticksmoduler" + #. TRANSLATORS: command description msgid "Merge multiple firmware files into one" msgstr "Sammanfoga flera fasta programvaror till en" @@ -467,11 +586,18 @@ msgstr "Övervaka demonen för händelser" msgid "Name" msgstr "Namn" +msgid "No action specified!" +msgstr "Ingen åtgärd angiven!" + #. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded msgid "No hardware detected with firmware update capability" msgstr "Ingen uppdateringsbar hårdvara upptäcktes" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Inga insticksmoduler hittades" + #. TRANSLATORS: explain why no metadata available msgid "No remotes are currently enabled so no metadata is available." msgstr "Inga fjärrar är aktiverade för närvarande, så ingen metadata är tillgänglig." @@ -481,7 +607,11 @@ msgstr "OK" #. TRANSLATORS: command line option msgid "Override plugin warning" -msgstr "Åsidosätt tilläggsvarning" +msgstr "Åsidosätt insticksmodulvarning" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Åsidosätt standardsökväg för ESP" #. TRANSLATORS: remote filename base msgid "Password" @@ -498,6 +628,12 @@ msgstr "Åtkomst nekad" msgid "Please enter a number from 0 to %u: " msgstr "Ange en siffra mellan 0 och %u: " +msgid "Print the version number" +msgstr "Skriv ut versionsnumret" + +msgid "Print verbose debug statements" +msgstr "Skriv ut utförliga felsökningssatser" + #. TRANSLATORS: the numeric priority msgid "Priority" msgstr "Prioritet" @@ -509,6 +645,10 @@ msgstr "Fortsätt med att skicka upp?" msgid "Protocol" msgstr "Protokoll" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Fråga efter stöd för uppdatering av fast programvara" + #. TRANSLATORS: device quirks, i.e. things that #. * it does that we have to work around msgid "Quirks" @@ -616,6 +756,10 @@ msgstr "Ange produkt-ID för den fasta programvarufilen" msgid "Set release version on firmware file" msgstr "Ange utgåveversion för den fasta programvarufilen" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Ställ in felsökningsflaggan under uppdatering" + #. TRANSLATORS: command description msgid "Set the firmware size for the target" msgstr "Ange fast programvarustorlek för målet" @@ -636,6 +780,10 @@ msgstr "Dela fast programvaruhistorik med utvecklarna" msgid "Show client and daemon versions" msgstr "Visa klient- och demon-version" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information" +msgstr "Visa utförlig information om demon" + #. TRANSLATORS: turn on all debugging msgid "Show debugging information for all files" msgstr "Visa felsökningsinformation för alla filer" @@ -644,18 +792,36 @@ msgstr "Visa felsökningsinformation för alla filer" msgid "Show debugging options" msgstr "Visa felsökningsalternativ" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Visa enheter som inte kan uppdateras" + #. TRANSLATORS: command line option msgid "Show extra debugging information" msgstr "Visa extra felsökningsinformation" #. TRANSLATORS: command description msgid "Show history of firmware updates" -msgstr "Visa historik över fasta programvaruupdateringar" +msgstr "Visa historik över fasta programvaruuppdateringar" #. TRANSLATORS: this is for plugin development msgid "Show plugin verbose information" msgstr "Visa utförlig information om insticksmodul" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Visa felsökningsloggen från det senaste uppdateringsförsöket" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Visa information om uppdateringsstatus för fast programvara" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Ange Tillverkar-/Produkt-ID för DFU-enhet" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Ange antalet byte per USB-överföring" + #. TRANSLATORS: device state, i.e. appIDLE msgid "State" msgstr "Tillstånd" @@ -673,6 +839,17 @@ msgstr "Sammanfattning" msgid "Target" msgstr "Mål" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS är en fri tjänst som fungerar som en oberoende juridisk person och har ingen koppling till $OS_RELEASE:NAME$. Din distributör kanske inte har bekräftat att någon av de fasta programvaruuppdateringarna är kompatibla med ditt system eller anslutna enheter. All fast programvara tillhandahålls endast av den ursprungliga tillverkaren av utrustning." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Detta program kommer endast fungera korrekt som root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Denna fjärrkälla innehåller fast programvara som inte är under embargo, men fortfarande testas av hårdvarutillverkare. Du bör säkerställa att du har ett sätt att manuellt nedgradera den fasta programvaran om uppdateringen misslyckas." + #. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" msgid "Title" msgstr "Titel" @@ -685,6 +862,10 @@ msgstr "Överföringsstorlek" msgid "Type" msgstr "Typ" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Verktyg för fast UEFI-programvara" + #. TRANSLATORS: section header for firmware URI msgid "URI" msgstr "URI" @@ -700,6 +881,10 @@ msgstr "Lås upp enheten för att tillåta åtkomst" msgid "Unlocks the device for firmware access" msgstr "Låser upp enheten för fast programvaruåtkomst" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Ta bort felsökningsflaggan under uppdatering" + #. TRANSLATORS: section header for firmware checksum msgid "Update Checksum" msgstr "Uppdateringskontrollsumma" @@ -708,6 +893,11 @@ msgstr "Uppdateringskontrollsumma" msgid "Update Description" msgstr "Uppdateringsbeskrivning" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Uppdateringslängd" + #. TRANSLATORS: section header for firmware remote http:// msgid "Update Location" msgstr "Uppdateringsplats" @@ -754,6 +944,11 @@ msgstr "Uppdaterar all fast programvara till de senast tillgängliga versionerna msgid "Updating %s from %s to %s... " msgstr "Uppdaterar %s från %s till %s... " +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Uppdaterar %s…" + #. TRANSLATORS: the server sent the user a small message msgid "Upload message:" msgstr "Uppladdningsmeddelande:" @@ -786,6 +981,10 @@ msgstr "Väntar..." msgid "Watch DFU devices being hotplugged" msgstr "Övervaka anslutna DFU-enheter" +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Övervaka hårdvaruändringar" + #. TRANSLATORS: command description msgid "Write firmware from file into device" msgstr "Skriv fast programvara från fil till enhet" diff --git a/po/uk.po b/po/uk.po index 27f7c6f70..ad1bd3268 100644 --- a/po/uk.po +++ b/po/uk.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the fwupd package. # # Translators: -# Yuri Chornoivan , 2015-2018 +# Yuri Chornoivan , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" @@ -90,10 +90,14 @@ msgstr "Дозволити зниження версій мікропрогра msgid "Allow re-installing existing firmware versions" msgstr "Дозволити повторне встановлення наявних версій мікропрограми" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "Для завершення оновлення слід перезавантажити систему." +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Для завершення оновлення систему слід вимкнути." + #. TRANSLATORS: command line option msgid "Answer yes to all questions" msgstr "Відповідати «так» на усі питання" @@ -520,12 +524,6 @@ msgstr "Встановити непідписану мікропрограму msgid "Install unsigned system firmware" msgstr "Встановити непідписану мікропрограму системи" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "Встановлюємо %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "Встановлюємо оновлення мікропрограми…" @@ -830,6 +828,10 @@ msgstr "Показати діагностичний журнал щодо ост msgid "Show the information of firmware update status" msgstr "Показати дані щодо стану оновлення мікропрограми" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Вимкнути зараз?" + msgid "Specify Vendor/Product ID(s) of DFU device" msgstr "Вказати ідентифікатори виробника/продукту пристрою DFU" @@ -857,10 +859,6 @@ msgstr "Ціль" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS є безкоштовною службою, яка працює як незалежна юридична одиниця і не має зв'язку з $OS_RELEASE:NAME$. Розробники вашої операційної системи, можливо, не перевіряли жодні з цих оновлень на сумісність із системою або з'єднаними із комп'ютером пристроями. Усі мікропрограми надаються лише самими виробниками обладнання." -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "Для завершення оновлення потрібне перезавантаження." - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "Програма зможе працювати належними чином лише від імені користувача root" @@ -936,6 +934,10 @@ msgstr "Резюме оновлення" msgid "Update Version" msgstr "Версія оновлення" +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Оновити усі пристрої, які відповідають локальним метаданим" + #. TRANSLATORS: the server sent the user a small message msgid "Update failure is a known issue, visit this URL for more information:" msgstr "Нам відомо про помилку під час оновлення. Будь ласка, відвідайте цю адресу, щоб дізнатися більше:" diff --git a/po/zh_CN.po b/po/zh_CN.po index c7c75f45b..32165fdff 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -49,7 +49,7 @@ msgstr "允许降级固件版本" msgid "Allow re-installing existing firmware versions" msgstr "允许重新安装现有的固件版本" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "更新需要重启设备才能完成。" diff --git a/po/zh_TW.po b/po/zh_TW.po index 52f8b62fc..3f13962a3 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -51,7 +51,7 @@ msgstr "允許降級韌體版本" msgid "Allow re-installing existing firmware versions" msgstr "允許重新安裝既有的韌體版本" -#. TRANSLATORS: explain why we want to upload +#. TRANSLATORS: explain why we want to reboot msgid "An update requires a reboot to complete." msgstr "有更新必須重新開機才能完成。" @@ -470,12 +470,6 @@ msgstr "安裝未簽署的裝置韌體" msgid "Install unsigned system firmware" msgstr "安裝未簽署的系統韌體" -#. show message in progressbar -#. TRANSLATORS: %1 is a device name -#, c-format -msgid "Installing %s" -msgstr "正安裝 %s" - #. TRANSLATORS: this is shown when updating the firmware after the reboot msgid "Installing firmware update…" msgstr "安裝韌體更新中…" @@ -791,10 +785,6 @@ msgstr "目標" msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." msgstr "LVFS(Linux 廠商韌體服務,Linux Vendor Firmware Service)是由獨立法人運作的免費服務,而與 $OS_RELEASE:NAME$ 沒有關聯。您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。所有本服務中的韌體僅由原始設備製造商提供。" -#. TRANSLATORS: exactly one update needs this -msgid "The update requires a reboot to complete." -msgstr "更新必須重新開機才能完成。" - #. TRANSLATORS: we're poking around as a power user msgid "This program may only work correctly as root" msgstr "此程式僅有 root 身份才能正常運作"