[gnome-software] Automatically download new firmware metadata from LVFS
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Automatically download new firmware metadata from LVFS
- Date: Thu, 25 Jun 2015 14:24:02 +0000 (UTC)
commit 86be7c79e50347c67ae6c8fe9539262f4423f642
Author: Richard Hughes <richard hughsie com>
Date: Thu Jun 25 15:08:50 2015 +0100
Automatically download new firmware metadata from LVFS
See https://beta-lvfs.rhcloud.com/ for more details.
src/plugins/gs-plugin-fwupd.c | 200 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 200 insertions(+), 0 deletions(-)
---
diff --git a/src/plugins/gs-plugin-fwupd.c b/src/plugins/gs-plugin-fwupd.c
index e541467..c6b85e2 100644
--- a/src/plugins/gs-plugin-fwupd.c
+++ b/src/plugins/gs-plugin-fwupd.c
@@ -41,6 +41,8 @@ struct GsPluginPrivate {
GPtrArray *to_ignore;
SoupSession *session;
gchar *cachedir;
+ gchar *lvfs_sig_fn;
+ gchar *lvfs_sig_hash;
};
/**
@@ -65,6 +67,9 @@ gs_plugin_fwupd_setup_networking (GsPlugin *plugin, GError **error)
plugin->name);
return FALSE;
}
+ /* this disables the double-compression of the firmware.xml.gz file */
+ soup_session_remove_feature_by_type (plugin->priv->session,
+ SOUP_TYPE_CONTENT_DECODER);
return TRUE;
}
@@ -96,6 +101,8 @@ void
gs_plugin_destroy (GsPlugin *plugin)
{
g_free (plugin->priv->cachedir);
+ g_free (plugin->priv->lvfs_sig_fn);
+ g_free (plugin->priv->lvfs_sig_hash);
g_object_unref (plugin->priv->store);
g_ptr_array_unref (plugin->priv->to_download);
g_ptr_array_unref (plugin->priv->to_ignore);
@@ -126,7 +133,9 @@ static gboolean
gs_plugin_startup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
{
gint rc;
+ gsize len;
_cleanup_error_free_ GError *error_local = NULL;
+ _cleanup_free_ gchar *data = NULL;
_cleanup_object_unref_ GDBusConnection *conn = NULL;
/* register D-Bus errors */
@@ -164,6 +173,18 @@ gs_plugin_startup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
return FALSE;
}
+ /* get the hash of the previously downloaded file */
+ plugin->priv->lvfs_sig_fn = g_build_filename (plugin->priv->cachedir,
+ "firmware.xml.gz.asc",
+ NULL);
+ if (g_file_test (plugin->priv->lvfs_sig_fn, G_FILE_TEST_EXISTS)) {
+ if (!g_file_get_contents (plugin->priv->lvfs_sig_fn,
+ &data, &len, error))
+ return FALSE;
+ plugin->priv->lvfs_sig_hash =
+ g_compute_checksum_for_data (G_CHECKSUM_SHA1, (guchar *) data, len);
+ }
+
/* only load firmware from the system */
as_store_add_filter (plugin->priv->store, AS_ID_KIND_FIRMWARE);
if (!as_store_load (plugin->priv->store,
@@ -535,6 +556,172 @@ gs_plugin_add_updates (GsPlugin *plugin,
}
/**
+ * gs_plugin_fwupd_update_lvfs_metadata:
+ */
+static gboolean
+gs_plugin_fwupd_update_lvfs_metadata (const gchar *data_fn, const gchar *sig_fn, GError **error)
+{
+ GVariant *body;
+ gint fd_sig;
+ gint fd_data;
+ gint retval;
+ _cleanup_object_unref_ GDBusConnection *conn = NULL;
+ _cleanup_object_unref_ GDBusMessage *message = NULL;
+ _cleanup_object_unref_ GDBusMessage *request = NULL;
+ _cleanup_object_unref_ GUnixFDList *fd_list = NULL;
+
+ conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
+ if (conn == NULL)
+ return FALSE;
+
+ /* open files */
+ fd_data = open (data_fn, O_RDONLY);
+ if (fd_data < 0) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "failed to open %s",
+ data_fn);
+ return FALSE;
+ }
+ fd_sig = open (sig_fn, O_RDONLY);
+ if (fd_sig < 0) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "failed to open %s",
+ sig_fn);
+ return FALSE;
+ }
+
+ /* set out of band file descriptor */
+ fd_list = g_unix_fd_list_new ();
+ retval = g_unix_fd_list_append (fd_list, fd_data, NULL);
+ retval = g_unix_fd_list_append (fd_list, fd_sig, NULL);
+ g_assert (retval != -1);
+ request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE,
+ FWUPD_DBUS_PATH,
+ FWUPD_DBUS_INTERFACE,
+ "UpdateMetadata");
+ g_dbus_message_set_unix_fd_list (request, fd_list);
+
+ /* g_unix_fd_list_append did a dup() already */
+ close (fd_data);
+ close (fd_sig);
+
+ /* send message */
+ body = g_variant_new ("(hh)", 0, 1);
+ g_dbus_message_set_body (request, body);
+ message = g_dbus_connection_send_message_with_reply_sync (conn,
+ request,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ error);
+ if (message == NULL) {
+ g_dbus_error_strip_remote_error (*error);
+ return FALSE;
+ }
+ if (g_dbus_message_to_gerror (message, error)) {
+ g_dbus_error_strip_remote_error (*error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_fwupd_check_lvfs_metadata:
+ */
+static gboolean
+gs_plugin_fwupd_check_lvfs_metadata (GsPlugin *plugin,
+ guint cache_age,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *url_data = "https://beta-lvfs.rhcloud.com/downloads/firmware.xml.gz";
+ guint status_code;
+ _cleanup_error_free_ GError *error_local = NULL;
+ _cleanup_free_ gchar *basename_data = NULL;
+ _cleanup_free_ gchar *cache_fn_data = NULL;
+ _cleanup_free_ gchar *checksum = NULL;
+ _cleanup_free_ gchar *url_sig = NULL;
+ _cleanup_object_unref_ SoupMessage *msg_data = NULL;
+ _cleanup_object_unref_ SoupMessage *msg_sig = NULL;
+
+ /* download the signature first, it's smaller */
+ url_sig = g_strdup_printf ("%s.asc", url_data);
+ msg_sig = soup_message_new (SOUP_METHOD_GET, url_sig);
+ status_code = soup_session_send_message (plugin->priv->session, msg_sig);
+ if (status_code != SOUP_STATUS_OK) {
+ g_warning ("Failed to download %s, ignoring: %s",
+ url_sig, soup_status_get_phrase (status_code));
+ return TRUE;
+ }
+
+ /* is the signature hash the same as we had before? */
+ checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1,
+ (const guchar *) msg_sig->response_body->data,
+ msg_sig->response_body->length);
+ if (g_strcmp0 (checksum, plugin->priv->lvfs_sig_hash) == 0) {
+ g_debug ("signature of %s is unchanged", url_sig);
+ return TRUE;
+ }
+
+ /* save to a file */
+ g_debug ("saving new LVFS signature to %s:", plugin->priv->lvfs_sig_fn);
+ if (!g_file_set_contents (plugin->priv->lvfs_sig_fn,
+ msg_sig->response_body->data,
+ msg_sig->response_body->length,
+ &error_local)) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Failed to save firmware: %s",
+ error_local->message);
+ return FALSE;
+ }
+
+ /* save the new checksum so we don't downoad the payload unless it's changed */
+ g_free (plugin->priv->lvfs_sig_hash);
+ plugin->priv->lvfs_sig_hash = g_strdup (checksum);
+
+ /* download the payload */
+ msg_data = soup_message_new (SOUP_METHOD_GET, url_data);
+ status_code = soup_session_send_message (plugin->priv->session, msg_data);
+ if (status_code != SOUP_STATUS_OK) {
+ g_warning ("Failed to download %s, ignoring: %s",
+ url_data, soup_status_get_phrase (status_code));
+ return TRUE;
+ }
+
+ /* save to a file */
+ basename_data = g_path_get_basename (url_data);
+ cache_fn_data = g_build_filename (plugin->priv->cachedir, basename_data, NULL);
+ g_debug ("saving new LVFS data to %s:", cache_fn_data);
+ if (!g_file_set_contents (cache_fn_data,
+ msg_data->response_body->data,
+ msg_data->response_body->length,
+ &error_local)) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Failed to save firmware: %s",
+ error_local->message);
+ return FALSE;
+ }
+
+ /* phew, lets send all this to fwupd */
+ if (!gs_plugin_fwupd_update_lvfs_metadata (cache_fn_data,
+ plugin->priv->lvfs_sig_fn,
+ error))
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
* gs_plugin_refresh:
*/
gboolean
@@ -545,12 +732,25 @@ gs_plugin_refresh (GsPlugin *plugin,
GError **error)
{
const gchar *tmp;
+ gboolean ret;
guint i;
+ /* set up plugin */
+ if (g_once_init_enter (&plugin->priv->done_init)) {
+ ret = gs_plugin_startup (plugin, cancellable, error);
+ g_once_init_leave (&plugin->priv->done_init, TRUE);
+ if (!ret)
+ return FALSE;
+ }
+
/* ensure networking is set up */
if (!gs_plugin_fwupd_setup_networking (plugin, error))
return FALSE;
+ /* get the metadata and signature file */
+ if (!gs_plugin_fwupd_check_lvfs_metadata (plugin, cache_age, cancellable, error))
+ return FALSE;
+
/* download the files to the cachedir */
for (i = 0; i < plugin->priv->to_download->len; i++) {
guint status_code;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]