From e4a100cfeea9fac82a9592e4da144cfa1f4022c9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sun, 4 Jun 2017 21:23:50 +0100 Subject: [PATCH] Add a GetReleases() D-Bus call to return all releases for a device This allows us to downgrade firmware in the future. --- libfwupd/fwupd-client.c | 67 ++++++++++++++++++ libfwupd/fwupd-client.h | 4 ++ src/fu-main.c | 82 +++++++++++++++++++++++ src/fu-util.c | 123 ++++++++++++++++++++++++---------- src/org.freedesktop.fwupd.xml | 30 +++++++++ 5 files changed, 271 insertions(+), 35 deletions(-) diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index ced9b63b2..705e2ff40 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -239,6 +239,28 @@ fwupd_client_parse_results_from_data (GVariant *devices) return results; } +static GPtrArray * +fwupd_client_parse_releases_from_variant (GVariant *val) +{ + FwupdRelease *release; + GPtrArray *releases = NULL; + gsize sz; + guint i; + g_autoptr(GVariant) untuple = NULL; + + releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (val, 0); + sz = g_variant_n_children (untuple); + for (i = 0; i < sz; i++) { + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + release = fwupd_release_new_from_data (data); + g_ptr_array_add (releases, release); + } + + return releases; +} + static void fwupd_client_fixup_dbus_error (GError *error) { @@ -351,6 +373,51 @@ fwupd_client_get_updates (FwupdClient *client, GCancellable *cancellable, GError return fwupd_client_parse_results_from_data (val); } +/** + * fwupd_client_get_releases: + * @client: A #FwupdClient + * @device_id: the device ID + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets all the releases for a specific device + * + * Returns: (element-type FwupdRelease) (transfer container): results + * + * Since: 0.9.3 + **/ +GPtrArray * +fwupd_client_get_releases (FwupdClient *client, const gchar *device_id, + GCancellable *cancellable, GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (device_id != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return NULL; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "GetReleases", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return NULL; + } + return fwupd_client_parse_releases_from_variant (val); +} + static void fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_data) { diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index aa5784a57..11806c68e 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -63,6 +63,10 @@ GPtrArray *fwupd_client_get_devices (FwupdClient *client, GPtrArray *fwupd_client_get_updates (FwupdClient *client, GCancellable *cancellable, GError **error); +GPtrArray *fwupd_client_get_releases (FwupdClient *client, + const gchar *device_id, + GCancellable *cancellable, + GError **error); GPtrArray *fwupd_client_get_details_local (FwupdClient *client, const gchar *filename, GCancellable *cancellable, diff --git a/src/fu-main.c b/src/fu-main.c index 514c716ee..03bb1372d 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -1585,6 +1585,54 @@ fu_main_get_updates (FuMainPrivate *priv, GError **error) return updates; } +/* find releases for a device */ +static GVariant * +fu_main_get_releases_to_variant (FuMainPrivate *priv, FuDeviceItem *item, GError **error) +{ + GPtrArray *device_guids; + GVariantBuilder builder; + g_autoptr(GPtrArray) results = NULL; + + /* get all the results for the device */ + results = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + device_guids = fu_device_get_guids (item->device); + for (guint i = 0; i < device_guids->len; i++) { + GPtrArray *releases; + const gchar *guid = g_ptr_array_index (device_guids, i); + AsApp *app = as_store_get_app_by_provide (priv->store, + AS_PROVIDE_KIND_FIRMWARE_FLASHED, + guid); + if (app == NULL) + continue; + releases = as_app_get_releases (app); + for (guint j = 0; j < releases->len; j++) { + AsRelease *release = g_ptr_array_index (releases, j); + FwupdRelease *rel = fwupd_release_new (); + fu_main_set_release_from_item (rel, release); + g_ptr_array_add (results, rel); + } + } + + /* no devices */ + if (results->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No releases for device"); + return NULL; + } + + /* convert the objects to a variant */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + for (guint i = 0; i < results->len; i++) { + GVariant *tmp; + FwupdRelease *rel = g_ptr_array_index (results, i); + tmp = fwupd_release_to_data (rel, "a{sv}"); //FIXME? + g_variant_builder_add_value (&builder, tmp); + } + return g_variant_new ("(aa{sv})", &builder); +} + static AsStore * fu_main_get_store_from_fd (FuMainPrivate *priv, gint fd, GError **error) { @@ -1840,6 +1888,40 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, return; } + /* return variant */ + if (g_strcmp0 (method_name, "GetReleases") == 0) { + FuDeviceItem *item; + const gchar *device_id = NULL; + g_autoptr(GPtrArray) releases = NULL; + + g_variant_get (parameters, "(&s)", &device_id); + g_debug ("Called %s(%s)", method_name, device_id); + + /* find the device */ + item = fu_main_get_item_by_id (priv, device_id); + if (item == NULL) { + g_set_error (&error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no device with ID %s", + device_id); + fu_main_invocation_return_error (priv, invocation, error); + return; + } + val = fu_main_get_releases_to_variant (priv, item, &error); + if (val == NULL) { + if (g_error_matches (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO)) { + g_prefix_error (&error, "No releases found: "); + } + fu_main_invocation_return_error (priv, invocation, error); + return; + } + fu_main_invocation_return_value (priv, invocation, val); + return; + } + /* return '' */ if (g_strcmp0 (method_name, "ClearResults") == 0) { FuDeviceItem *item = NULL; diff --git a/src/fu-util.c b/src/fu-util.c index f864ab479..c553bea2a 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -268,6 +268,27 @@ fu_util_client_notify_cb (GObject *object, fu_util_display_panel (priv); } +static void +fu_util_print_data (const gchar *title, const gchar *msg) +{ + gsize title_len; + g_auto(GStrv) lines = NULL; + + if (msg == NULL) + return; + g_print ("%s:", title); + + /* pad */ + title_len = strlen (title) + 1; + lines = g_strsplit (msg, "\n", -1); + for (guint j = 0; lines[j] != NULL; j++) { + for (gsize i = title_len; i < 25; i++) + g_print (" "); + g_print ("%s\n", lines[j]); + title_len = 0; + } +} + static gboolean fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -806,6 +827,67 @@ fu_util_get_results (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static const gchar * +_g_checksum_type_to_string (GChecksumType checksum_type) +{ + if (checksum_type == G_CHECKSUM_MD5) + return "md5"; + 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 NULL; +} + +static gboolean +fu_util_get_releases (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) rels = NULL; + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: expected 'DeviceID'"); + return FALSE; + } + rels = fwupd_client_get_releases (priv->client, values[0], NULL, error); + if (rels == NULL) + return FALSE; + for (guint i = 0; i < rels->len; i++) { + FwupdRelease *rel = g_ptr_array_index (rels, i); + const gchar *tmp = fwupd_release_get_description (rel); + + /* TRANSLATORS: section header for release version number */ + fu_util_print_data (_("Version"), fwupd_release_get_version (rel)); + + /* TRANSLATORS: section header for firmware URI */ + fu_util_print_data (_("URI"), fwupd_release_get_uri (rel)); + tmp = fwupd_release_get_description (rel); + if (tmp != NULL) { + g_autofree gchar *desc = NULL; + desc = as_markup_convert_simple (tmp, NULL); + /* TRANSLATORS: section header for firmware description */ + fu_util_print_data (_("Description"), desc); + } + + /* TRANSLATORS: section header for firmware checksum */ + fu_util_print_data (_("Checksum"), fwupd_release_get_checksum (rel)); + if (fwupd_release_get_checksum (rel) != NULL) { + GChecksumType checksum_type = fwupd_release_get_checksum_kind (rel); + tmp = _g_checksum_type_to_string (checksum_type); + /* TRANSLATORS: section header for firmware checksum type */ + fu_util_print_data (_("Checksum Type"), tmp); + } + + /* new line between all but last entries */ + if (i != rels->len - 1) + g_print ("\n"); + } + return TRUE; +} + static gboolean fu_util_verify_all (FuUtilPrivate *priv, GError **error) { @@ -865,41 +947,6 @@ fu_util_unlock (FuUtilPrivate *priv, gchar **values, GError **error) return fwupd_client_unlock (priv->client, values[0], NULL, error); } -static void -fu_util_print_data (const gchar *title, const gchar *msg) -{ - gsize title_len; - g_auto(GStrv) lines = NULL; - - if (msg == NULL) - return; - g_print ("%s:", title); - - /* pad */ - title_len = strlen (title) + 1; - lines = g_strsplit (msg, "\n", -1); - for (guint j = 0; lines[j] != NULL; j++) { - for (gsize i = title_len; i < 25; i++) - g_print (" "); - g_print ("%s\n", lines[j]); - title_len = 0; - } -} - -static const gchar * -_g_checksum_type_to_string (GChecksumType checksum_type) -{ - if (checksum_type == G_CHECKSUM_MD5) - return "md5"; - 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 NULL; -} - static gboolean fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1308,6 +1355,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Gets the results from the last update"), fu_util_get_results); + fu_util_add (priv->cmd_array, + "get-releases", + NULL, + /* TRANSLATORS: command description */ + _("Gets the releases for a device"), + fu_util_get_releases); fu_util_add (priv->cmd_array, "refresh", NULL, diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index dd19b46f0..0a864d151 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -80,6 +80,36 @@ + + + + + + Gets a list of all the releases for a specific device. + + + + + + + + A device ID. + + + + + + + + + An array of releases (with the release number as the key), + with any properties set on each. + + + + + +