Add a GetReleases() D-Bus call to return all releases for a device

This allows us to downgrade firmware in the future.
This commit is contained in:
Richard Hughes 2017-06-04 21:23:50 +01:00
parent fdce4f57a3
commit e4a100cfee
5 changed files with 271 additions and 35 deletions

View File

@ -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)
{

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -80,6 +80,36 @@
</arg>
</method>
<!--***********************************************************-->
<method name='GetReleases'>
<doc:doc>
<doc:description>
<doc:para>
Gets a list of all the releases for a specific device.
</doc:para>
</doc:description>
</doc:doc>
<arg type='s' name='device_id' direction='in'>
<doc:doc>
<doc:summary>
<doc:para>
A device ID.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type='aa{sv}' name='releases' direction='out'>
<doc:doc>
<doc:summary>
<doc:para>
An array of releases (with the release number as the key),
with any properties set on each.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
</method>
<!--***********************************************************-->
<method name='GetDetails'>
<doc:doc>