diff --git a/src/fu-hwids.c b/src/fu-hwids.c new file mode 100644 index 000000000..5407f873a --- /dev/null +++ b/src/fu-hwids.c @@ -0,0 +1,315 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2017 Richard Hughes + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "fu-hwids.h" + +struct _FuHwids { + GObject parent_instance; + GHashTable *hash; +}; + +G_DEFINE_TYPE (FuHwids, fu_hwids, G_TYPE_OBJECT) + +const gchar * +fu_hwids_get_value (FuHwids *self, const gchar *key) +{ + return g_hash_table_lookup (self->hash, key); +} + +static gchar * +fu_hwids_get_guid_for_str (const gchar *str, GError **error) +{ +#if AS_CHECK_VERSION(0,6,13) + const gchar *namespace_id = "70ffd812-4c7f-4c7d-0000-000000000000"; + glong items_written = 0; + g_autofree gunichar2 *data = NULL; + + /* convert to UTF-16 and convert to GUID using custom namespace */ + data = g_utf8_to_utf16 (str, -1, NULL, &items_written, error); + if (data == NULL) + return NULL; + return as_utils_guid_from_data (namespace_id, + (guint8*) data, + items_written * 2, + error); +#else + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "libappstream-glib 0.6.13 is required"); + return FALSE; +#endif +} + +/** + * fu_hwids_get_replace_keys: + * @self: A #FuHwids + * @key: A HardwareID key, e.g. "HardwareID-3" + * + * Gets the replacement key for a well known value. + * + * Returns: the replacement value, e.g. "Manufacturer&ProductName", or %NULL for error. + **/ +const gchar * +fu_hwids_get_replace_keys (FuHwids *self, const gchar *key) +{ + struct { + const gchar *search; + const gchar *replace; + } msdefined[] = { + { "HardwareID-0", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY "&" + FU_HWIDS_KEY_PRODUCT_NAME "&" + FU_HWIDS_KEY_PRODUCT_SKU "&" + FU_HWIDS_KEY_BIOS_VENDOR "&" + FU_HWIDS_KEY_BIOS_VERSION "&" + FU_HWIDS_KEY_BIOS_MAJOR_RELEASE "&" + FU_HWIDS_KEY_BIOS_MINOR_RELEASE }, + { "HardwareID-1", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY "&" + FU_HWIDS_KEY_PRODUCT_NAME "&" + FU_HWIDS_KEY_BIOS_VENDOR "&" + FU_HWIDS_KEY_BIOS_VERSION "&" + FU_HWIDS_KEY_BIOS_MAJOR_RELEASE "&" + FU_HWIDS_KEY_BIOS_MINOR_RELEASE }, + { "HardwareID-2", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_PRODUCT_NAME "&" + FU_HWIDS_KEY_BIOS_VENDOR "&" + FU_HWIDS_KEY_BIOS_VERSION "&" + FU_HWIDS_KEY_BIOS_MAJOR_RELEASE "&" + FU_HWIDS_KEY_BIOS_MINOR_RELEASE }, + { "HardwareID-3", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY "&" + FU_HWIDS_KEY_PRODUCT_NAME "&" + FU_HWIDS_KEY_PRODUCT_SKU "&" + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER "&" + FU_HWIDS_KEY_BASEBOARD_PRODUCT }, + { "HardwareID-4", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY "&" + FU_HWIDS_KEY_PRODUCT_NAME "&" + FU_HWIDS_KEY_PRODUCT_SKU }, + { "HardwareID-5", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY "&" + FU_HWIDS_KEY_PRODUCT_NAME }, + { "HardwareID-6", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_PRODUCT_SKU "&" + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER "&" + FU_HWIDS_KEY_BASEBOARD_PRODUCT }, + { "HardwareID-7", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_PRODUCT_SKU }, + { "HardwareID-8", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_PRODUCT_NAME "&" + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER "&" + FU_HWIDS_KEY_BASEBOARD_PRODUCT }, + { "HardwareID-9", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_PRODUCT_NAME }, + { "HardwareID-10", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY "&" + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER "&" + FU_HWIDS_KEY_BASEBOARD_PRODUCT }, + { "HardwareID-11", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_FAMILY }, + { "HardwareID-12", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_ENCLOSURE_KIND }, + { "HardwareID-13", FU_HWIDS_KEY_MANUFACTURER "&" + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER "&" + FU_HWIDS_KEY_BASEBOARD_PRODUCT }, + { "HardwareID-14", FU_HWIDS_KEY_MANUFACTURER }, + { NULL, NULL } + }; + + /* defined for Windows 10 */ + for (guint i = 0; msdefined[i].search != NULL; i++) { + if (g_strcmp0 (msdefined[i].search, key) == 0) { + key = msdefined[i].replace; + break; + } + } + + return key; +} + +/** + * fu_hwids_get_replace_values: + * @self: A #FuHwids + * @keys: A key, e.g. "HardwareID-3" or %FU_HWIDS_KEY_PRODUCT_SKU + * @error: A #GError or %NULL + * + * Gets the replacement values for a HardwareID key or plain key. + * + * Returns: a string, e.g. "LENOVO&ThinkPad T440s", or %NULL for error. + **/ +gchar * +fu_hwids_get_replace_values (FuHwids *self, const gchar *keys, GError **error) +{ + g_auto(GStrv) split = NULL; + g_autoptr(GString) str = g_string_new (NULL); + + /* do any replacements */ + keys = fu_hwids_get_replace_keys (self, keys); + + /* get each part of the HWID */ + split = g_strsplit (keys, "&", -1); + for (guint j = 0; split[j] != NULL; j++) { + const gchar *tmp = g_hash_table_lookup (self->hash, split[j]); + if (tmp == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "not available as '%s' unknown", + split[j]); + return NULL; + } + g_string_append_printf (str, "%s&", tmp); + } + if (str->len > 0) + g_string_truncate (str, str->len - 1); + return g_strdup (str->str); +} + +/** + * fu_hwids_get_guid: + * @self: A #FuHwids + * @keys: A key, e.g. "HardwareID-3" or %FU_HWIDS_KEY_PRODUCT_SKU + * @error: A #GError or %NULL + * + * Gets the GUID for a specific key. + * + * Returns: a string, or %NULL for error. + **/ +gchar * +fu_hwids_get_guid (FuHwids *self, const gchar *keys, GError **error) +{ + g_autofree gchar *tmp = fu_hwids_get_replace_values (self, keys, error); + if (tmp == NULL) + return NULL; + return fu_hwids_get_guid_for_str (tmp, error); +} + +/** + * fu_hwids_setup: + * @self: A #FuHwids + * @sysfsdir: The sysfs directory, or %NULL for the default + * @error: A #GError or %NULL + * + * Reads all the SMBIOS values from the hardware. + * + * Returns: %TRUE for success + **/ +gboolean +fu_hwids_setup (FuHwids *self, const gchar *sysfsdir, GError **error) +{ + struct { + const gchar *key; + const gchar *value; + } sysfsfile[] = { + { FU_HWIDS_KEY_MANUFACTURER, "sys_vendor" }, + { FU_HWIDS_KEY_ENCLOSURE_KIND, "chassis_type" }, + { FU_HWIDS_KEY_FAMILY, "product_family" }, + { FU_HWIDS_KEY_PRODUCT_NAME, "product_name" }, + { FU_HWIDS_KEY_PRODUCT_SKU, "product_sku" }, + { FU_HWIDS_KEY_BIOS_VENDOR, "bios_vendor" }, + { FU_HWIDS_KEY_BIOS_VERSION, "bios_version" }, + { FU_HWIDS_KEY_BIOS_MAJOR_RELEASE, "bios_major_release" }, + { FU_HWIDS_KEY_BIOS_MINOR_RELEASE, "bios_minor_release" }, + { FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, "board_vendor" }, + { FU_HWIDS_KEY_BASEBOARD_PRODUCT, "board_name" }, + { NULL, NULL } + }; + + g_return_val_if_fail (FU_IS_HWIDS (self), FALSE); + + /* default value */ + if (sysfsdir == NULL) + sysfsdir = "/sys/class/dmi/id"; + + /* does not exist in a container */ + if (!g_file_test (sysfsdir, G_FILE_TEST_EXISTS)) + return TRUE; + + /* get all DMI data */ + for (guint i = 0; sysfsfile[i].key != NULL; i++) { + g_autofree gchar *contents = NULL; + g_autofree gchar *fn = NULL; + const gchar *contents_hdr; + + fn = g_build_filename (sysfsdir, sysfsfile[i].value, NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_debug ("no %s so ignoring", fn); + continue; + } + if (!g_file_get_contents (fn, &contents, NULL, error)) + return FALSE; + g_strdelimit (contents, "\n\r", '\0'); + g_debug ("smbios property %s=%s", fn, contents); + if (g_strcmp0 (contents, "Not Available") == 0) + continue; + if (g_strcmp0 (contents, "Not Defined") == 0) + continue; + + /* weirdly, remove leading zeros */ + contents_hdr = contents; + while (contents_hdr[0] == '0') + contents_hdr++; + g_hash_table_insert (self->hash, + g_strdup (sysfsfile[i].key), + g_strdup (contents_hdr)); + } + + return TRUE; +} + +static void +fu_hwids_finalize (GObject *object) +{ + FuHwids *self; + g_return_if_fail (FU_IS_HWIDS (object)); + self = FU_HWIDS (object); + + g_hash_table_unref (self->hash); + G_OBJECT_CLASS (fu_hwids_parent_class)->finalize (object); +} + +static void +fu_hwids_class_init (FuHwidsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_hwids_finalize; +} + +static void +fu_hwids_init (FuHwids *self) +{ + self->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); +} + +FuHwids * +fu_hwids_new (void) +{ + FuHwids *self; + self = g_object_new (FU_TYPE_HWIDS, NULL); + return FU_HWIDS (self); +} diff --git a/src/fu-hwids.h b/src/fu-hwids.h new file mode 100644 index 000000000..eaf1c6790 --- /dev/null +++ b/src/fu-hwids.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2017 Richard Hughes + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __FU_HWIDS_H +#define __FU_HWIDS_H + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_HWIDS (fu_hwids_get_type ()) + +G_DECLARE_FINAL_TYPE (FuHwids, fu_hwids, FU, HWIDS, GObject) + +#define FU_HWIDS_KEY_BASEBOARD_MANUFACTURER "BaseboardManufacturer" +#define FU_HWIDS_KEY_BASEBOARD_PRODUCT "BaseboardProduct" +#define FU_HWIDS_KEY_BIOS_MAJOR_RELEASE "BiosMajorRelease" +#define FU_HWIDS_KEY_BIOS_MINOR_RELEASE "BiosMinorRelease" +#define FU_HWIDS_KEY_BIOS_VENDOR "BiosVendor" +#define FU_HWIDS_KEY_BIOS_VERSION "BiosVersion" +#define FU_HWIDS_KEY_ENCLOSURE_KIND "EnclosureKind" +#define FU_HWIDS_KEY_FAMILY "Family" +#define FU_HWIDS_KEY_MANUFACTURER "Manufacturer" +#define FU_HWIDS_KEY_PRODUCT_NAME "ProductName" +#define FU_HWIDS_KEY_PRODUCT_SKU "ProductSku" + +FuHwids *fu_hwids_new (void); + +const gchar *fu_hwids_get_value (FuHwids *self, + const gchar *key); +const gchar *fu_hwids_get_replace_keys (FuHwids *self, + const gchar *key); +gchar *fu_hwids_get_replace_values (FuHwids *self, + const gchar *keys, + GError **error); +gchar *fu_hwids_get_guid (FuHwids *self, + const gchar *keys, + GError **error); +gboolean fu_hwids_setup (FuHwids *self, + const gchar *sysfsdir, + GError **error); + +G_END_DECLS + +#endif /* __FU_HWIDS_H */ diff --git a/src/fu-main.c b/src/fu-main.c index ec595cf61..adafd9c8f 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -38,6 +38,7 @@ #include "fu-debug.h" #include "fu-device.h" +#include "fu-hwids.h" #include "fu-plugin-private.h" #include "fu-keyring.h" #include "fu-pending.h" @@ -72,6 +73,7 @@ typedef struct { guint coldplug_delay; GPtrArray *plugins; /* of FuPlugin */ GHashTable *plugins_hash; /* of name : FuPlugin */ + GHashTable *hwids; /* of hwid : 1 */ } FuMainPrivate; typedef struct { @@ -2666,6 +2668,41 @@ fu_main_plugin_set_coldplug_delay_cb (FuPlugin *plugin, guint duration, FuMainPr duration, priv->coldplug_delay); } +static gboolean +fu_main_load_hwids (FuMainPrivate *priv, GError **error) +{ + g_autoptr(FuHwids) hwids = fu_hwids_new (); + + /* read files in /sys */ + if (!fu_hwids_setup (hwids, NULL, error)) + return FALSE; + + /* add GUIDs */ + 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 */ + key = g_strdup_printf ("HardwareID-%u", i); + guid = fu_hwids_get_guid (hwids, key, &error_local); + if (guid == NULL) { + g_debug ("%s is not available, %s", key, error_local->message); + continue; + } + g_hash_table_insert (priv->hwids, + g_strdup (guid), + GUINT_TO_POINTER (1)); + + /* show what makes up the GUID */ + values = fu_hwids_get_replace_values (hwids, key, NULL); + g_debug ("{%s} <- %s", guid, values); + } + + return TRUE; +} + static gboolean fu_main_load_plugins (FuMainPrivate *priv, GError **error) { @@ -2697,6 +2734,7 @@ fu_main_load_plugins (FuMainPrivate *priv, GError **error) filename = g_build_filename (PLUGINDIR, fn, NULL); plugin = fu_plugin_new (); fu_plugin_set_usb_context (plugin, priv->usb_ctx); + fu_plugin_set_hwids (plugin, priv->hwids); g_debug ("adding plugin %s", filename); if (!fu_plugin_open (plugin, filename, &error_local)) { g_warning ("failed to open plugin %s: %s", @@ -2818,6 +2856,8 @@ fu_main_private_free (FuMainPrivate *priv) g_source_remove (priv->coldplug_id); if (priv->plugins != NULL) g_ptr_array_unref (priv->plugins); + if (priv->hwids != NULL) + g_hash_table_unref (priv->hwids); if (priv->plugins_hash != NULL) g_hash_table_unref (priv->plugins_hash); g_ptr_array_unref (priv->devices); @@ -2911,6 +2951,13 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + /* load the hwids */ + priv->hwids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + if (!fu_main_load_hwids (priv, &error)) { + g_printerr ("Failed to load hwids: %s\n", error->message); + return EXIT_FAILURE; + } + /* load plugin */ priv->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->plugins_hash = g_hash_table_new_full (g_str_hash, g_str_equal, diff --git a/src/fu-plugin-private.h b/src/fu-plugin-private.h index b9603de41..648b4b362 100644 --- a/src/fu-plugin-private.h +++ b/src/fu-plugin-private.h @@ -31,6 +31,8 @@ G_BEGIN_DECLS FuPlugin *fu_plugin_new (void); void fu_plugin_set_usb_context (FuPlugin *plugin, GUsbContext *usb_ctx); +void fu_plugin_set_hwids (FuPlugin *plugin, + GHashTable *hwids); gboolean fu_plugin_open (FuPlugin *plugin, const gchar *filename, GError **error); diff --git a/src/fu-plugin.c b/src/fu-plugin.c index 11eb8b2f0..bfd8bc860 100644 --- a/src/fu-plugin.c +++ b/src/fu-plugin.c @@ -43,6 +43,7 @@ typedef struct { GUsbContext *usb_ctx; gboolean enabled; gchar *name; + GHashTable *hwids; /* hwid:1 */ GHashTable *devices; /* platform_id:GObject */ GHashTable *devices_delay; /* FuDevice:FuPluginHelper */ FuPluginData *data; @@ -484,6 +485,34 @@ fu_plugin_recoldplug (FuPlugin *plugin) g_signal_emit (plugin, signals[SIGNAL_RECOLDPLUG], 0); } +/** + * fu_plugin_check_hwid: + * @plugin: A #FuPlugin + * @hwid: A Hardware ID GUID, e.g. "6de5d951-d755-576b-bd09-c5cf66b27234" + * + * Checks to see if a specific hardware ID exists. All hardware IDs on a + * specific system can be shown using the `fwupdmgr hwids` command. + * + * Since: 0.9.1 + **/ +gboolean +fu_plugin_check_hwid (FuPlugin *plugin, const gchar *hwid) +{ + FuPluginPrivate *priv = GET_PRIVATE (plugin); + if (priv->hwids == NULL) + return FALSE; + return g_hash_table_lookup (priv->hwids, hwid) != NULL; +} + +void +fu_plugin_set_hwids (FuPlugin *plugin, GHashTable *hwids) +{ + FuPluginPrivate *priv = GET_PRIVATE (plugin); + if (priv->hwids != NULL) + g_hash_table_unref (priv->hwids); + priv->hwids = g_hash_table_ref (hwids); +} + /** * fu_plugin_set_coldplug_delay: * @plugin: A #FuPlugin @@ -1086,6 +1115,8 @@ fu_plugin_finalize (GObject *object) if (priv->usb_ctx != NULL) g_object_unref (priv->usb_ctx); + if (priv->hwids != NULL) + g_hash_table_unref (priv->hwids); #ifndef RUNNING_ON_VALGRIND if (priv->module != NULL) g_module_close (priv->module); diff --git a/src/fu-plugin.h b/src/fu-plugin.h index 45df0495f..12366bf41 100644 --- a/src/fu-plugin.h +++ b/src/fu-plugin.h @@ -92,6 +92,8 @@ void fu_plugin_cache_remove (FuPlugin *plugin, void fu_plugin_cache_add (FuPlugin *plugin, const gchar *id, gpointer dev); +gboolean fu_plugin_check_hwid (FuPlugin *plugin, + const gchar *hwid); G_END_DECLS diff --git a/src/fu-self-test.c b/src/fu-self-test.c index c57b4592b..4d1199999 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -30,8 +30,71 @@ #include "fu-keyring.h" #include "fu-pending.h" #include "fu-plugin-private.h" +#include "fu-hwids.h" #include "fu-test.h" +static void +fu_hwids_func (void) +{ + g_autoptr(FuHwids) hwids = NULL; + g_autoptr(GError) error = NULL; + g_autofree gchar *guid = NULL; + g_autofree gchar *testdir = NULL; + const gchar *sysfsdir; + gboolean ret; + + struct { + const gchar *key; + const gchar *value; + } guids[] = { + { "Manufacturer", "11b4a036-3b64-5421-a372-22c07df10a4d" }, + { "HardwareID-14", "11b4a036-3b64-5421-a372-22c07df10a4d" }, + { "HardwareID-13", "7ccbb6f1-9641-5f84-b00d-51ff218a4066" }, + { "HardwareID-12", "482f3f58-6045-593a-9be4-611717ce4770" }, + { "HardwareID-11", "6525c6e5-28e9-5f9c-abe4-20fd82504002" }, + { "HardwareID-10", "c00fe015-014c-5301-90d1-b5c8ab037eb4" }, + { "HardwareID-9", "6525c6e5-28e9-5f9c-abe4-20fd82504002" }, + { "HardwareID-8", "c00fe015-014c-5301-90d1-b5c8ab037eb4" }, + { "HardwareID-7", "5a127cba-be28-5d3b-84f0-0e450d266d97" }, + { "HardwareID-6", "2c2d02cc-357e-539d-a44d-d10e902391dd" }, + { "HardwareID-5", "7ccbb6f1-9641-5f84-b00d-51ff218a4066" }, + { "HardwareID-4", "d78b474d-dee0-5412-bc9d-e9f7d7783df2" }, + { "HardwareID-3", "a2f225b3-f4f0-5590-8973-08dd81602d69" }, + { "HardwareID-2", "2e7c87e3-a52c-537f-a5f6-907110143cf7" }, + { "HardwareID-1", "6453b900-1fd8-55fb-a936-7fca22823bcc" }, + { "HardwareID-0", "d777e0a5-4db6-51b4-a927-86d4ccdc5c0d" }, + { NULL, NULL } + }; + + sysfsdir = fu_test_get_filename (TESTDATADIR, "hwids"); + g_assert (sysfsdir != NULL); + + hwids = fu_hwids_new (); + ret = fu_hwids_setup (hwids, sysfsdir, &error); + g_assert_no_error (error); + g_assert (ret); + + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_MANUFACTURER), ==, + "To be filled by O.E.M."); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_ENCLOSURE_KIND), ==, + "3"); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_FAMILY), ==, + "To be filled by O.E.M."); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_PRODUCT_NAME), ==, + "To be filled by O.E.M."); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_VENDOR), ==, + "American Megatrends Inc."); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_VERSION), ==, "1201"); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE), ==, "4"); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MINOR_RELEASE), ==, "6"); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_PRODUCT_SKU), ==, "SKU"); + for (guint i = 0; guids[i].key != NULL; i++) { + guid = fu_hwids_get_guid (hwids, guids[i].key, &error); + g_assert_no_error (error); + g_assert_cmpstr (guid, ==, guids[i].value); + } +} + static void _plugin_status_changed_cb (FuPlugin *plugin, FwupdStatus status, gpointer user_data) { @@ -347,6 +410,7 @@ main (int argc, char **argv) g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); /* tests go here */ + g_test_add_func ("/fwupd/hwids", fu_hwids_func); g_test_add_func ("/fwupd/pending", fu_pending_func); g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func); g_test_add_func ("/fwupd/plugin{module}", fu_plugin_module_func); diff --git a/src/fu-util.c b/src/fu-util.c index f02908a3f..b62f2f7c5 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2015-2016 Richard Hughes + * Copyright (C) 2015-2017 Richard Hughes * * Licensed under the GNU General Public License Version 2 * @@ -36,6 +36,7 @@ #include #include +#include "fu-hwids.h" #include "fu-pending.h" #include "fu-plugin-private.h" @@ -1074,6 +1075,67 @@ fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_hwids (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuHwids) hwids = fu_hwids_new (); + const gchar *hwid_keys[] = { + FU_HWIDS_KEY_BIOS_VENDOR, + FU_HWIDS_KEY_BIOS_VERSION, + FU_HWIDS_KEY_BIOS_MAJOR_RELEASE, + FU_HWIDS_KEY_BIOS_MINOR_RELEASE, + FU_HWIDS_KEY_MANUFACTURER, + FU_HWIDS_KEY_FAMILY, + FU_HWIDS_KEY_PRODUCT_NAME, + FU_HWIDS_KEY_PRODUCT_SKU, + FU_HWIDS_KEY_ENCLOSURE_KIND, + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, + FU_HWIDS_KEY_BASEBOARD_PRODUCT, + NULL }; + + /* read files in /sys */ + if (!fu_hwids_setup (hwids, g_getenv ("SYSFSPATH"), error)) + return FALSE; + + /* show debug output */ + g_print ("Computer Information\n"); + g_print ("--------------------\n"); + for (guint i = 0; hwid_keys[i] != NULL; i++) { + const gchar *tmp = fu_hwids_get_value (hwids, hwid_keys[i]); + if (tmp == NULL) + continue; + g_print ("%s: %s\n", hwid_keys[i], tmp); + } + + /* show GUIDs */ + g_print ("\nHardware IDs\n"); + g_print ("------------\n"); + for (guint i = 0; i < 15; i++) { + const gchar *keys = NULL; + g_autofree gchar *guid = NULL; + g_autofree gchar *key = NULL; + g_autofree gchar *keys_str = NULL; + g_auto(GStrv) keysv = NULL; + g_autoptr(GError) error_local = NULL; + + /* get the GUID */ + key = g_strdup_printf ("HardwareID-%u", i); + keys = fu_hwids_get_replace_keys (hwids, key); + guid = fu_hwids_get_guid (hwids, key, &error_local); + if (guid == NULL) { + g_print ("%s\n", error_local->message); + continue; + } + + /* show what makes up the GUID */ + keysv = g_strsplit (keys, "&", -1); + keys_str = g_strjoinv (" + ", keysv); + g_print ("{%s} <- %s\n", guid, keys_str); + } + + return TRUE; +} + static void fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) @@ -1156,6 +1218,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Get all devices that support firmware updates"), fu_util_get_devices); + fu_util_add (priv->cmd_array, + "hwids", + NULL, + /* TRANSLATORS: command description */ + _("Return all the hardare IDs for the machine"), + fu_util_hwids); fu_util_add (priv->cmd_array, "install-prepared", NULL, diff --git a/src/meson.build b/src/meson.build index 8673b4717..3f792cf72 100644 --- a/src/meson.build +++ b/src/meson.build @@ -9,6 +9,7 @@ executable( sources : [ 'fu-device.c', 'fu-pending.c', + 'fu-hwids.c', 'fu-util.c', ], include_directories : [ @@ -46,6 +47,7 @@ executable( resources_src, sources : [ 'fu-main.c', + 'fu-hwids.c', 'fu-debug.c', 'fu-device.c', 'fu-keyring.c', @@ -88,6 +90,7 @@ if get_option('enable-tests') colorhug_test_firmware, sources : [ 'fu-self-test.c', + 'fu-hwids.c', 'fu-device.c', 'fu-pending.c', 'fu-keyring.c',