aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hardinfo/info.c13
-rw-r--r--hardinfo/util.c20
-rw-r--r--includes/hardinfo.h1
-rw-r--r--includes/info.h1
-rw-r--r--modules/devices/firmware.c275
5 files changed, 171 insertions, 139 deletions
diff --git a/hardinfo/info.c b/hardinfo/info.c
index f888ddac..2d1d4159 100644
--- a/hardinfo/info.c
+++ b/hardinfo/info.c
@@ -431,6 +431,19 @@ gchar *info_flatten(struct Info *info)
return g_string_free(values, FALSE);
}
+void info_remove_group(struct Info *info, guint index)
+{
+ struct InfoGroup *grp;
+
+ if (index >= info->groups->len)
+ return;
+
+ grp = &g_array_index(info->groups, struct InfoGroup, index);
+ free_group_fields(grp);
+
+ g_array_remove_index(info->groups, index);
+}
+
struct InfoField *info_find_field(struct Info *info, const gchar *tag, const gchar *name) {
struct InfoGroup *group;
struct InfoField *field;
diff --git a/hardinfo/util.c b/hardinfo/util.c
index b1db6922..89c3ffd4 100644
--- a/hardinfo/util.c
+++ b/hardinfo/util.c
@@ -1349,6 +1349,26 @@ gboolean g_strv_contains(const gchar * const * strv, const gchar *str) {
}
#endif
+gchar *hardinfo_clean_grpname(const gchar *v, int replacing) {
+ gchar *clean, *p;
+
+ p = clean = g_strdup(v);
+ while (*p != 0) {
+ switch(*p) {
+ case '[':
+ *p = '('; break;
+ case ']':
+ *p = ')'; break;
+ default:
+ break;
+ }
+ p++;
+ }
+ if (replacing)
+ g_free((gpointer)v);
+ return clean;
+}
+
/* Hardinfo labels that have # are truncated and/or hidden.
* Labels can't have $ because that is the delimiter in
* moreinfo. */
diff --git a/includes/hardinfo.h b/includes/hardinfo.h
index d8ff20d6..19eb88fb 100644
--- a/includes/hardinfo.h
+++ b/includes/hardinfo.h
@@ -193,6 +193,7 @@ gboolean g_strv_contains(const gchar * const * strv, const gchar *str);
gchar *
gg_key_file_parse_string_as_value (const gchar *string, const gchar list_separator);
+gchar *hardinfo_clean_grpname(const gchar *v, int replacing);
/* Hardinfo labels that have # are truncated and/or hidden.
* Labels can't have $ because that is the delimiter in
* moreinfo.
diff --git a/includes/info.h b/includes/info.h
index 794e3679..8f31c61a 100644
--- a/includes/info.h
+++ b/includes/info.h
@@ -75,6 +75,7 @@ struct InfoField {
struct Info *info_new(void);
+void info_remove_group(struct Info *info, guint index);
struct InfoGroup *info_add_group(struct Info *info, const gchar *group_name, ...);
void info_group_strip_extra(struct InfoGroup *group);
diff --git a/modules/devices/firmware.c b/modules/devices/firmware.c
index f3191503..6c283d6e 100644
--- a/modules/devices/firmware.c
+++ b/modules/devices/firmware.c
@@ -2,6 +2,7 @@
* HardInfo - Displays System Information
* Copyright (C) 2003-2019 Leandro A. F. Pereira <leandro@hardinfo.org>
* Copyright (C) 2019 Burt P. <pburt0@gmail.com>
+ * Copyright (C) 2020 Ondrej Čerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,85 +18,54 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/* TODO Consider: https://fwupd.org/lvfs/docs/users -> "Using the D-Bus API" */
-
-/* Example `fwupdmgr get-devices`:
-Unifying Receiver
- DeviceId: ecd8ed6144290e36b8d2587116f9d3543d3c69b7
- Guid: 9d131a0c-a606-580f-8eda-80587250b8d6
- Guid: 279ed287-3607-549e-bacc-f873bb9838c4
- Guid: 21e75d9a-5ce6-5da2-b7ab-910c7f3f6836
- Summary: A miniaturised USB wireless receiver
- Plugin: unifying
- Flags: updatable|supported|registered
- Vendor: Logitech
- VendorId: USB:0x046D
- Version: RQR12.09_B0030
- VersionBootloader: BOT01.04_B0016
- Icon: preferences-desktop-keyboard
- InstallDuration: 7
- Created: 2019-07-22
-*/
-/* sudo example:
-Unifying Receiver
- DeviceId: ecd8ed6144290e36b8d2587116f9d3543d3c69b7
- Guid: 9d131a0c-a606-580f-8eda-80587250b8d6
- Guid: 279ed287-3607-549e-bacc-f873bb9838c4 <- HIDRAW\VEN_046D&DEV_C52B
- Guid: 21e75d9a-5ce6-5da2-b7ab-910c7f3f6836 <- HIDRAW\VEN_046D
- Summary: A miniaturised USB wireless receiver
- Plugin: unifying
- Flags: updatable|supported|registered
- Vendor: Logitech
- VendorId: USB:0x046D
- Version: RQR12.09_B0030
- VersionBootloader: BOT01.04_B0016
- Icon: preferences-desktop-keyboard
- InstallDuration: 7
- Created: 2019-07-26
-*/
-
#include "hardinfo.h"
#include "devices.h"
#include <inttypes.h>
+#include <gio/gio.h>
#include "util_sysobj.h" /* for SEQ() and appf() */
#define fw_msg(msg, ...) fprintf (stderr, "[%s] " msg "\n", __FUNCTION__, ##__VA_ARGS__) /**/
-gboolean fail_no_fwupdmgr = TRUE;
+#define FWUPT_INTERFACE "org.freedesktop.fwupd"
-const char *find_flag_definition(const char *flag) {
+gboolean fail_no_fwupd = TRUE;
+
+char *decode_flags(guint64 flags) {
/* https://github.com/hughsie/fwupd/blob/master/libfwupd/fwupd-enums.{h,c} */
- static const struct { char *flag, *def; } flag_defs[] = {
- { "internal", N_("Device cannot be removed easily") },
- { "updatable", N_("Device is updatable in this or any other mode") },
- { "only-offline", N_("Update can only be done from offline mode") },
- { "require-ac", N_("Requires AC power") },
- { "locked", N_("Is locked and can be unlocked") },
- { "supported", N_("Is found in current metadata") },
- { "needs-bootloader", N_("Requires a bootloader mode to be manually enabled by the user") },
- { "registered", N_("Has been registered with other plugins") },
- { "needs-reboot", N_("Requires a reboot to apply firmware or to reload hardware") },
- { "needs-shutdown", N_("Requires system shutdown to apply firmware") },
- { "reported", N_("Has been reported to a metadata server") },
- { "notified", N_("User has been notified") },
- { "use-runtime-version", N_("Always use the runtime version rather than the bootloader") },
- { "install-parent-first", N_("Install composite firmware on the parent before the child") },
- { "is-bootloader", N_("Is currently in bootloader mode") },
- { "wait-for-replug", N_("The hardware is waiting to be replugged") },
- { "ignore-validation", N_("Ignore validation safety checks when flashing this device") },
- { "another-write-required", N_("Requires the update to be retried with a new plugin") },
- { "no-auto-instance-ids", N_("Do not add instance IDs from the device baseclass") },
- { "needs-activation", N_("Device update needs to be separately activated") },
- { "ensure-semver", N_("Ensure the version is a valid semantic version, e.g. numbers separated with dots") },
- { "trusted", N_("Extra metadata can be exposed about this device") },
- { NULL }
+ static const struct { guint64 b; char *flag, *def; } flag_defs[] = {
+ { (1u << 0), "internal", N_("Device cannot be removed easily") },
+ { (1u << 1), "updatable", N_("Device is updatable in this or any other mode") },
+ { (1u << 2), "only-offline", N_("Update can only be done from offline mode") },
+ { (1u << 3), "require-ac", N_("Requires AC power") },
+ { (1u << 4), "locked", N_("Is locked and can be unlocked") },
+ { (1u << 5), "supported", N_("Is found in current metadata") },
+ { (1u << 6), "needs-bootloader", N_("Requires a bootloader mode to be manually enabled by the user") },
+ { (1u << 7), "registered", N_("Has been registered with other plugins") },
+ { (1u << 8), "needs-reboot", N_("Requires a reboot to apply firmware or to reload hardware") },
+ { (1u << 17), "needs-shutdown", N_("Requires system shutdown to apply firmware") },
+ { (1u << 9), "reported", N_("Has been reported to a metadata server") },
+ { (1u << 10), "notified", N_("User has been notified") },
+ { (1u << 11), "use-runtime-version", N_("Always use the runtime version rather than the bootloader") },
+ { (1u << 12), "install-parent-first", N_("Install composite firmware on the parent before the child") },
+ { (1u << 13), "is-bootloader", N_("Is currently in bootloader mode") },
+ { (1u << 14), "wait-for-replug", N_("The hardware is waiting to be replugged") },
+ { (1u << 15), "ignore-validation", N_("Ignore validation safety checks when flashing this device") },
+ { (1u << 18), "another-write-required", N_("Requires the update to be retried with a new plugin") },
+ { (1u << 19), "no-auto-instance-ids", N_("Do not add instance IDs from the device baseclass") },
+ { (1u << 20), "needs-activation", N_("Device update needs to be separately activated") },
+ { (1u << 21), "ensure-semver", N_("Ensure the version is a valid semantic version, e.g. numbers separated with dots") },
+ { (1u << 16), "trusted", N_("Extra metadata can be exposed about this device") },
+ { 0, NULL }
};
+
+ gchar *flag_list = g_strdup("");
+
int i;
for (i = 0; flag_defs[i].flag; i++) {
- if (SEQ(flag, flag_defs[i].flag))
- return flag_defs[i].def;
+ if (flags & flag_defs[i].b)
+ flag_list = appfnl(flag_list, "[%s] %s", flag_defs[i].flag, flag_defs[i].def);
}
- return NULL;
+ return flag_list;
}
const char *find_translation(const char *str) {
@@ -143,99 +113,126 @@ const char *find_icon(const char *lvfs_name) {
}
gchar *fwupdmgr_get_devices_info() {
- gboolean spawned;
- gchar *out, *err, *p, *next_nl, *col;
- gint exit_status;
-
struct Info *info = info_new();
-
struct InfoGroup *this_group = NULL;
gboolean has_vendor_field = FALSE;
+ gboolean updatable = FALSE;
const Vendor *gv = NULL;
int gc = 0;
- fail_no_fwupdmgr = FALSE;
- spawned = g_spawn_command_line_sync("fwupdmgr get-devices",
- &out, &err, &exit_status, NULL);
- if (spawned) {
- p = out;
- while(next_nl = strchr(p, '\n')) {
- *next_nl = 0;
- if (!isspace(*p) && *p != 0) {
- if (gv && !has_vendor_field) {
- info_group_add_field(this_group,
- info_field(_("Vendor"), gv->name,
+ GDBusConnection *conn;
+ GDBusProxy *proxy;
+ GVariant *devices, *value;
+ GVariantIter *deviter, *dictiter, *iter;
+ const gchar *key, *tmpstr;
+
+ conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
+ if (!conn)
+ return g_strdup("");
+
+ proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
+ FWUPT_INTERFACE, "/", FWUPT_INTERFACE,
+ NULL, NULL);
+ if (!proxy) {
+ g_object_unref(conn);
+ return g_strdup("");
+ }
+
+ fail_no_fwupd = FALSE;
+ devices = g_dbus_proxy_call_sync(proxy, "GetDevices", NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
+
+ if (devices) {
+ g_variant_get(devices, "(aa{sv})", &deviter);
+ while(g_variant_iter_loop(deviter, "a{sv}", &dictiter)){
+
+ this_group = info_add_group(info, _("Unknown"), info_field_last());
+ this_group->sort = INFO_GROUP_SORT_NAME_DESCENDING;
+ has_vendor_field = FALSE;
+ updatable = FALSE;
+ gv = NULL;
+
+ while (g_variant_iter_loop(dictiter, "{&sv}", &key, &value)) {
+ if (SEQ(key, "Name")) {
+ tmpstr = g_variant_get_string(value, NULL);
+ this_group->name = hardinfo_clean_grpname(tmpstr, 0);
+ gv = vendor_match(tmpstr, NULL);
+ } else if (SEQ(key, "Vendor")) {
+ has_vendor_field = TRUE;
+ tmpstr = g_variant_get_string(value, NULL);
+
+ const Vendor* v = vendor_match(tmpstr, NULL);
+ if (v) {
+ info_group_add_field(this_group,
+ info_field(_("Vendor"), v->name,
.value_has_vendor = TRUE,
.free_value_on_flatten = FALSE) );
- }
- g_strstrip(p);
- this_group = info_add_group(info, g_strdup(p), info_field_last());
- this_group->sort = INFO_GROUP_SORT_NAME_DESCENDING;
- gv = vendor_match(p, NULL);
- has_vendor_field = FALSE;
- } else {
- if (col = strchr(p, ':')) {
- *col = 0;
- g_strstrip(p); // name
- g_strstrip(col+1); // value
- if (SEQ(p, "Icon")) {
+ } else {
info_group_add_field(this_group,
- info_field(find_translation(p), g_strdup(col+1),
- .free_value_on_flatten = TRUE, .icon = g_strdup(find_icon(col+1)) ) );
- } else if (SEQ(p, "Vendor")) {
- has_vendor_field = TRUE;
- const Vendor* v = vendor_match(col+1, NULL);
- if (v) {
- info_group_add_field(this_group,
- info_field(_("Vendor"), v->name,
- .value_has_vendor = TRUE,
- .free_value_on_flatten = FALSE) );
- } else {
- info_group_add_field(this_group,
- info_field(find_translation(p), g_strdup(col+1),
- .free_value_on_flatten = TRUE) );
- }
- } else if (SEQ(p, "Guid")) {
- gchar *ar = NULL;
- if (ar = strstr(col+1, " <-"))
- *ar = 0;
+ info_field(_("Vendor"), g_strdup(tmpstr),
+ .free_value_on_flatten = TRUE) );
+ }
+ } else if (SEQ(key, "Icon")) {
+ g_variant_get(value, "as", &iter);
+ while (g_variant_iter_loop(iter, "s", &tmpstr)) {
info_group_add_field(this_group,
- info_field(find_translation(p), g_strdup(col+1),
+ info_field(_("Icon"), g_strdup(tmpstr),
+ .free_value_on_flatten = TRUE,
+ .icon = g_strdup(find_icon(tmpstr)) ) );
+ }
+ } else if (SEQ(key, "Guid")) {
+ g_variant_get(value, "as", &iter);
+ while (g_variant_iter_loop(iter, "s", &tmpstr)) {
+ info_group_add_field(this_group,
+ info_field(_("Guid"), g_strdup(tmpstr),
.tag = g_strdup_printf("guid%d", gc++),
.free_value_on_flatten = TRUE) );
- } else if (SEQ(p, "Flags")) {
- gchar **flags = g_strsplit(col+1, "|", 0);
- gchar *flag_list = g_strdup("");
- int f = 0;
- for(; flags[f]; f++) {
- const char *lf = find_flag_definition(flags[f]);
- flag_list = appfnl(flag_list, "[%s] %s", flags[f], lf ? lf : "");
- }
+ }
+ g_variant_iter_free(iter);
+ } else if (SEQ(key, "Created")) {
+ guint64 created = g_variant_get_uint64(value);
+ GDateTime *dt = g_date_time_new_from_unix_local(created);
+ if (dt) {
info_group_add_field(this_group,
- info_field(find_translation(p), flag_list,
+ info_field(_("Created"), g_date_time_format(dt, "%x"),
+ .free_value_on_flatten = TRUE) );
+ g_date_time_unref(dt);
+ }
+ } else if (SEQ(key, "Flags")) {
+ guint64 flags = g_variant_get_uint64(value);
+ updatable = (gboolean)(flags & (1u << 1));
+ info_group_add_field(this_group,
+ info_field(_("Flags"), decode_flags(flags),
.free_value_on_flatten = TRUE) );
- } else
+ } else {
+ if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
info_group_add_field(this_group,
- info_field(find_translation(p), g_strdup(col+1),
+ info_field(find_translation(key),
+ g_variant_dup_string(value, NULL),
.free_value_on_flatten = TRUE) );
+ }
}
}
- p = next_nl + 1;
- }
- if (gv && !has_vendor_field) {
- info_group_add_field(this_group,
- info_field(_("Vendor"), gv->name,
- .value_has_vendor = TRUE,
- .free_value_on_flatten = FALSE) );
- }
+ if (gv && !has_vendor_field) {
+ info_group_add_field(this_group,
+ info_field(_("Vendor"), gv->name,
+ .value_has_vendor = TRUE,
+ .free_value_on_flatten = FALSE) );
+ }
- g_free(out);
- g_free(err);
- } else {
- fail_no_fwupdmgr = TRUE;
+ // hide devices that are not updatable
+ if (!updatable) {
+ info_remove_group(info, info->groups->len - 1);
+ }
+ }
+ g_variant_iter_free(deviter);
+ g_variant_unref(devices);
}
+ g_object_unref(proxy);
+ g_object_unref(conn);
+
gchar *ret = NULL;
if (info->groups->len) {
info_set_view_type(info, SHELL_VIEW_DETAIL);
@@ -255,9 +252,9 @@ gchar *firmware_get_info() {
}
gboolean firmware_hinote(const char **msg) {
- if (fail_no_fwupdmgr) {
+ if (fail_no_fwupd) {
*msg = g_strdup(
- _("Requires the <i><b>fwupdmgr</b></i> utility."));
+ _("Requires the <i><b>fwupd</b></i> daemon."));
return TRUE;
}
return FALSE;