mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-21 16:54:55 +00:00
941 lines
25 KiB
C
941 lines
25 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
*
|
|
* Copyright (C) 2016 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* 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 "config.h"
|
|
|
|
#include <glib-object.h>
|
|
#include <gio/gio.h>
|
|
#include <gio/gunixfdlist.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "fwupd-client.h"
|
|
#include "fwupd-enums.h"
|
|
#include "fwupd-error.h"
|
|
#include "fwupd-result.h"
|
|
|
|
static void fwupd_client_finalize (GObject *object);
|
|
|
|
/**
|
|
* FwupdClientPrivate:
|
|
*
|
|
* Private #FwupdClient data
|
|
**/
|
|
typedef struct {
|
|
FwupdStatus status;
|
|
GDBusConnection *conn;
|
|
GDBusProxy *proxy;
|
|
} FwupdClientPrivate;
|
|
|
|
enum {
|
|
SIGNAL_CHANGED,
|
|
SIGNAL_STATUS_CHANGED,
|
|
SIGNAL_LAST
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_STATUS,
|
|
PROP_LAST
|
|
};
|
|
|
|
static guint signals [SIGNAL_LAST] = { 0 };
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (FwupdClient, fwupd_client, G_TYPE_OBJECT)
|
|
#define GET_PRIVATE(o) (fwupd_client_get_instance_private (o))
|
|
|
|
typedef struct {
|
|
gboolean ret;
|
|
GError *error;
|
|
GMainLoop *loop;
|
|
GVariant *val;
|
|
GDBusMessage *message;
|
|
} FwupdClientHelper;
|
|
|
|
/**
|
|
* fwupd_client_helper_free:
|
|
**/
|
|
static void
|
|
fwupd_client_helper_free (FwupdClientHelper *helper)
|
|
{
|
|
if (helper->message != NULL)
|
|
g_object_unref (helper->message);
|
|
if (helper->val != NULL)
|
|
g_variant_unref (helper->val);
|
|
if (helper->error != NULL)
|
|
g_error_free (helper->error);
|
|
g_main_loop_unref (helper->loop);
|
|
g_free (helper);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_helper_new:
|
|
**/
|
|
static FwupdClientHelper *
|
|
fwupd_client_helper_new (void)
|
|
{
|
|
FwupdClientHelper *helper;
|
|
helper = g_new0 (FwupdClientHelper, 1);
|
|
helper->loop = g_main_loop_new (NULL, FALSE);
|
|
return helper;
|
|
}
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free)
|
|
|
|
/**
|
|
* fwupd_client_properties_changed_cb:
|
|
**/
|
|
static void
|
|
fwupd_client_properties_changed_cb (GDBusProxy *proxy,
|
|
GVariant *changed_properties,
|
|
GStrv invalidated_properties,
|
|
FwupdClient *client)
|
|
{
|
|
g_autoptr(GVariant) val = NULL;
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
|
|
/* print to the console */
|
|
val = g_dbus_proxy_get_cached_property (proxy, "Status");
|
|
if (val == NULL)
|
|
return;
|
|
priv->status = g_variant_get_uint32 (val);
|
|
g_debug ("Emitting ::status-changed() [%s]", fwupd_status_to_string (priv->status));
|
|
g_signal_emit (client, signals[SIGNAL_STATUS_CHANGED], 0, priv->status);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_signal_cb:
|
|
*/
|
|
static void
|
|
fwupd_client_signal_cb (GDBusProxy *proxy,
|
|
const gchar *sender_name,
|
|
const gchar *signal_name,
|
|
GVariant *parameters,
|
|
FwupdClient *client)
|
|
{
|
|
g_debug ("Emitting ::changed()");
|
|
g_signal_emit (client, signals[SIGNAL_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_startup:
|
|
**/
|
|
static gboolean
|
|
fwupd_client_startup (FwupdClient *client, GCancellable *cancellable, GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
|
|
g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
|
|
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
/* nothing to do */
|
|
if (priv->proxy != NULL)
|
|
return TRUE;
|
|
|
|
/* connect to the daemon */
|
|
priv->conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
|
|
if (priv->conn == NULL)
|
|
return FALSE;
|
|
priv->proxy = g_dbus_proxy_new_sync (priv->conn,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
NULL,
|
|
FWUPD_DBUS_SERVICE,
|
|
FWUPD_DBUS_PATH,
|
|
FWUPD_DBUS_INTERFACE,
|
|
NULL,
|
|
error);
|
|
if (priv->proxy == NULL)
|
|
return FALSE;
|
|
g_signal_connect (priv->proxy, "g-properties-changed",
|
|
G_CALLBACK (fwupd_client_properties_changed_cb), client);
|
|
g_signal_connect (priv->proxy, "g-signal",
|
|
G_CALLBACK (fwupd_client_signal_cb), client);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_parse_results_from_data:
|
|
**/
|
|
static GPtrArray *
|
|
fwupd_client_parse_results_from_data (GVariant *devices)
|
|
{
|
|
FwupdResult *res;
|
|
GPtrArray *results = NULL;
|
|
gsize sz;
|
|
guint i;
|
|
g_autoptr(GVariant) untuple = NULL;
|
|
|
|
results = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
|
untuple = g_variant_get_child_value (devices, 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);
|
|
res = fwupd_result_new_from_data (data);
|
|
g_ptr_array_add (results, res);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_get_devices:
|
|
* @client: A #FwupdClient
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Gets all the devices registered with the daemon.
|
|
*
|
|
* Returns: (element-type FwupdResult) (transfer container): results
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
GPtrArray *
|
|
fwupd_client_get_devices (FwupdClient *client, 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 (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
/* connect */
|
|
if (!fwupd_client_startup (client, cancellable, error))
|
|
return NULL;
|
|
|
|
/* call into daemon */
|
|
val = g_dbus_proxy_call_sync (priv->proxy,
|
|
"GetDevices",
|
|
NULL,
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
cancellable,
|
|
error);
|
|
if (val == NULL) {
|
|
if (error != NULL)
|
|
g_dbus_error_strip_remote_error (*error);
|
|
return NULL;
|
|
}
|
|
return fwupd_client_parse_results_from_data (val);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_get_updates:
|
|
* @client: A #FwupdClient
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Gets all the devices with known updates.
|
|
*
|
|
* Returns: (element-type FwupdResult) (transfer container): results
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
GPtrArray *
|
|
fwupd_client_get_updates (FwupdClient *client, 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 (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
/* connect */
|
|
if (!fwupd_client_startup (client, cancellable, error))
|
|
return NULL;
|
|
|
|
/* call into daemon */
|
|
val = g_dbus_proxy_call_sync (priv->proxy,
|
|
"GetUpdates",
|
|
NULL,
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
cancellable,
|
|
error);
|
|
if (val == NULL) {
|
|
if (error != NULL)
|
|
g_dbus_error_strip_remote_error (*error);
|
|
return NULL;
|
|
}
|
|
return fwupd_client_parse_results_from_data (val);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_proxy_call_cb:
|
|
**/
|
|
static void
|
|
fwupd_client_proxy_call_cb (GObject *source, GAsyncResult *res, gpointer user_data)
|
|
{
|
|
FwupdClientHelper *helper = (FwupdClientHelper *) user_data;
|
|
helper->val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source),
|
|
res, &helper->error);
|
|
if (helper->val != NULL)
|
|
helper->ret = TRUE;
|
|
if (helper->error != NULL)
|
|
g_dbus_error_strip_remote_error (helper->error);
|
|
g_main_loop_quit (helper->loop);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_verify:
|
|
* @client: A #FwupdClient
|
|
* @device_id: the device ID
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Verify a specific device.
|
|
*
|
|
* Returns: %TRUE for verification success
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
gboolean
|
|
fwupd_client_verify (FwupdClient *client, const gchar *device_id,
|
|
GCancellable *cancellable, GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
g_autoptr(FwupdClientHelper) helper = NULL;
|
|
g_autoptr(GVariant) val = NULL;
|
|
|
|
g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
|
|
g_return_val_if_fail (device_id != NULL, FALSE);
|
|
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
/* connect */
|
|
if (!fwupd_client_startup (client, cancellable, error))
|
|
return FALSE;
|
|
|
|
/* call into daemon */
|
|
helper = fwupd_client_helper_new ();
|
|
g_dbus_proxy_call (priv->proxy,
|
|
"Verify",
|
|
g_variant_new ("(s)", device_id),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
cancellable,
|
|
fwupd_client_proxy_call_cb,
|
|
helper);
|
|
g_main_loop_run (helper->loop);
|
|
if (!helper->ret) {
|
|
g_propagate_error (error, helper->error);
|
|
helper->error = NULL;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_unlock:
|
|
* @client: A #FwupdClient
|
|
* @device_id: the device ID
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Unlocks a specific device so firmware can be read or wrote.
|
|
*
|
|
* Returns: %TRUE for success
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
gboolean
|
|
fwupd_client_unlock (FwupdClient *client, const gchar *device_id,
|
|
GCancellable *cancellable, GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
g_autoptr(FwupdClientHelper) helper = NULL;
|
|
g_autoptr(GVariant) val = NULL;
|
|
|
|
g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
|
|
g_return_val_if_fail (device_id != NULL, FALSE);
|
|
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
/* connect */
|
|
if (!fwupd_client_startup (client, cancellable, error))
|
|
return FALSE;
|
|
|
|
/* call into daemon */
|
|
helper = fwupd_client_helper_new ();
|
|
g_dbus_proxy_call (priv->proxy,
|
|
"Unlock",
|
|
g_variant_new ("(s)", device_id),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
cancellable,
|
|
fwupd_client_proxy_call_cb,
|
|
helper);
|
|
g_main_loop_run (helper->loop);
|
|
if (!helper->ret) {
|
|
g_propagate_error (error, helper->error);
|
|
helper->error = NULL;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_clear_results:
|
|
* @client: A #FwupdClient
|
|
* @device_id: the device ID
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Clears the results for a specific device.
|
|
*
|
|
* Returns: %TRUE for success
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
gboolean
|
|
fwupd_client_clear_results (FwupdClient *client, const gchar *device_id,
|
|
GCancellable *cancellable, GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
g_autoptr(FwupdClientHelper) helper = NULL;
|
|
g_autoptr(GVariant) val = NULL;
|
|
|
|
g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
|
|
g_return_val_if_fail (device_id != NULL, FALSE);
|
|
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
/* connect */
|
|
if (!fwupd_client_startup (client, cancellable, error))
|
|
return FALSE;
|
|
|
|
/* call into daemon */
|
|
helper = fwupd_client_helper_new ();
|
|
g_dbus_proxy_call (priv->proxy,
|
|
"ClearResults",
|
|
g_variant_new ("(s)", device_id),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
cancellable,
|
|
fwupd_client_proxy_call_cb,
|
|
helper);
|
|
g_main_loop_run (helper->loop);
|
|
if (!helper->ret) {
|
|
g_propagate_error (error, helper->error);
|
|
helper->error = NULL;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_get_results:
|
|
* @client: A #FwupdClient
|
|
* @device_id: the device ID
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Gets the results of a previous firmware update for a specific device.
|
|
*
|
|
* Returns: (transfer full): a #FwupdResult, or %NULL for failure
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
FwupdResult *
|
|
fwupd_client_get_results (FwupdClient *client, const gchar *device_id,
|
|
GCancellable *cancellable, GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
g_autoptr(FwupdClientHelper) helper = NULL;
|
|
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_startup (client, cancellable, error))
|
|
return NULL;
|
|
|
|
/* call into daemon */
|
|
helper = fwupd_client_helper_new ();
|
|
g_dbus_proxy_call (priv->proxy,
|
|
"GetResults",
|
|
g_variant_new ("(s)", device_id),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
cancellable,
|
|
fwupd_client_proxy_call_cb,
|
|
helper);
|
|
g_main_loop_run (helper->loop);
|
|
if (!helper->ret) {
|
|
g_propagate_error (error, helper->error);
|
|
helper->error = NULL;
|
|
return NULL;
|
|
}
|
|
return fwupd_result_new_from_data (helper->val);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_send_message_cb:
|
|
**/
|
|
static void
|
|
fwupd_client_send_message_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
|
{
|
|
FwupdClientHelper *helper = (FwupdClientHelper *) user_data;
|
|
GDBusConnection *con = G_DBUS_CONNECTION (source_object);
|
|
helper->message = g_dbus_connection_send_message_with_reply_finish (con, res,
|
|
&helper->error);
|
|
if (helper->message &&
|
|
!g_dbus_message_to_gerror (helper->message, &helper->error)) {
|
|
helper->ret = TRUE;
|
|
helper->val = g_dbus_message_get_body (helper->message);
|
|
if (helper->val != NULL)
|
|
g_variant_ref (helper->val);
|
|
}
|
|
if (helper->error != NULL)
|
|
g_dbus_error_strip_remote_error (helper->error);
|
|
g_main_loop_quit (helper->loop);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_install:
|
|
* @client: A #FwupdClient
|
|
* @device_id: the device ID
|
|
* @filename: the filename to install
|
|
* @install_flags: the #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Install a file onto a specific device.
|
|
*
|
|
* Returns: %TRUE for success
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
gboolean
|
|
fwupd_client_install (FwupdClient *client,
|
|
const gchar *device_id,
|
|
const gchar *filename,
|
|
FwupdInstallFlags install_flags,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
GVariant *body;
|
|
GVariantBuilder builder;
|
|
gint retval;
|
|
gint fd;
|
|
g_autoptr(FwupdClientHelper) helper = NULL;
|
|
g_autoptr(GDBusMessage) request = NULL;
|
|
g_autoptr(GUnixFDList) fd_list = NULL;
|
|
g_autoptr(GVariant) val = NULL;
|
|
|
|
g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
|
|
g_return_val_if_fail (device_id != NULL, FALSE);
|
|
g_return_val_if_fail (filename != NULL, FALSE);
|
|
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
/* connect */
|
|
if (!fwupd_client_startup (client, cancellable, error))
|
|
return FALSE;
|
|
|
|
/* set options */
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
|
|
g_variant_builder_add (&builder, "{sv}",
|
|
"reason", g_variant_new_string ("user-action"));
|
|
g_variant_builder_add (&builder, "{sv}",
|
|
"filename", g_variant_new_string (filename));
|
|
if (install_flags & FWUPD_INSTALL_FLAG_OFFLINE) {
|
|
g_variant_builder_add (&builder, "{sv}",
|
|
"offline", g_variant_new_boolean (TRUE));
|
|
}
|
|
if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) {
|
|
g_variant_builder_add (&builder, "{sv}",
|
|
"allow-older", g_variant_new_boolean (TRUE));
|
|
}
|
|
if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) {
|
|
g_variant_builder_add (&builder, "{sv}",
|
|
"allow-reinstall", g_variant_new_boolean (TRUE));
|
|
}
|
|
|
|
/* open file */
|
|
fd = open (filename, O_RDONLY);
|
|
if (fd < 0) {
|
|
g_set_error (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"failed to open %s",
|
|
filename);
|
|
return FALSE;
|
|
}
|
|
|
|
/* set out of band file descriptor */
|
|
fd_list = g_unix_fd_list_new ();
|
|
retval = g_unix_fd_list_append (fd_list, fd, NULL);
|
|
g_assert (retval != -1);
|
|
request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE,
|
|
FWUPD_DBUS_PATH,
|
|
FWUPD_DBUS_INTERFACE,
|
|
"Install");
|
|
g_dbus_message_set_unix_fd_list (request, fd_list);
|
|
|
|
/* g_unix_fd_list_append did a dup() already */
|
|
close (fd);
|
|
|
|
/* call into daemon */
|
|
helper = fwupd_client_helper_new ();
|
|
body = g_variant_new ("(sha{sv})", device_id, fd > -1 ? 0 : -1, &builder);
|
|
g_dbus_message_set_body (request, body);
|
|
g_dbus_connection_send_message_with_reply (priv->conn,
|
|
request,
|
|
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
|
|
-1,
|
|
NULL,
|
|
cancellable,
|
|
fwupd_client_send_message_cb,
|
|
helper);
|
|
g_main_loop_run (helper->loop);
|
|
if (!helper->ret) {
|
|
g_propagate_error (error, helper->error);
|
|
helper->error = NULL;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_get_details:
|
|
* @client: A #FwupdClient
|
|
* @filename: the firmware filename, e.g. "firmware.cab"
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Gets details about a specific firmware file.
|
|
*
|
|
* Returns: (transfer full): a #FwupdResult, or %NULL for failure
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
FwupdResult *
|
|
fwupd_client_get_details (FwupdClient *client, const gchar *filename,
|
|
GCancellable *cancellable, GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
GVariant *body;
|
|
gint fd;
|
|
gint retval;
|
|
g_autoptr(FwupdClientHelper) helper = NULL;
|
|
g_autoptr(GDBusMessage) request = NULL;
|
|
g_autoptr(GUnixFDList) fd_list = NULL;
|
|
|
|
g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL);
|
|
g_return_val_if_fail (filename != 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_startup (client, cancellable, error))
|
|
return NULL;
|
|
|
|
/* open file */
|
|
fd = open (filename, O_RDONLY);
|
|
if (fd < 0) {
|
|
g_set_error (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"failed to open %s",
|
|
filename);
|
|
return NULL;
|
|
}
|
|
|
|
/* set out of band file descriptor */
|
|
fd_list = g_unix_fd_list_new ();
|
|
retval = g_unix_fd_list_append (fd_list, fd, NULL);
|
|
g_assert (retval != -1);
|
|
request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE,
|
|
FWUPD_DBUS_PATH,
|
|
FWUPD_DBUS_INTERFACE,
|
|
"GetDetails");
|
|
g_dbus_message_set_unix_fd_list (request, fd_list);
|
|
|
|
/* g_unix_fd_list_append did a dup() already */
|
|
close (fd);
|
|
|
|
/* call into daemon */
|
|
helper = fwupd_client_helper_new ();
|
|
body = g_variant_new ("(h)", fd > -1 ? 0 : -1);
|
|
g_dbus_message_set_body (request, body);
|
|
|
|
g_dbus_connection_send_message_with_reply (priv->conn,
|
|
request,
|
|
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
|
|
-1,
|
|
NULL,
|
|
cancellable,
|
|
fwupd_client_send_message_cb,
|
|
helper);
|
|
g_main_loop_run (helper->loop);
|
|
if (!helper->ret) {
|
|
g_propagate_error (error, helper->error);
|
|
helper->error = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
/* print results */
|
|
return fwupd_result_new_from_data (helper->val);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_update_metadata:
|
|
* @client: A #FwupdClient
|
|
* @metadata_fn: the XML metadata filename
|
|
* @signature_fn: the GPG signature file
|
|
* @cancellable: the #GCancellable, or %NULL
|
|
* @error: the #GError, or %NULL
|
|
*
|
|
* Updates the metadata. This allows a session process to download the metadata
|
|
* and metadata signing file to be passed into the daemon to be checked and
|
|
* parsed.
|
|
*
|
|
* Returns: %TRUE for success
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
gboolean
|
|
fwupd_client_update_metadata (FwupdClient *client,
|
|
const gchar *metadata_fn,
|
|
const gchar *signature_fn,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
GVariant *body;
|
|
gint fd;
|
|
gint fd_sig;
|
|
g_autoptr(FwupdClientHelper) helper = NULL;
|
|
g_autoptr(GDBusMessage) request = NULL;
|
|
g_autoptr(GUnixFDList) fd_list = NULL;
|
|
|
|
g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE);
|
|
g_return_val_if_fail (metadata_fn != NULL, FALSE);
|
|
g_return_val_if_fail (signature_fn != NULL, FALSE);
|
|
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
/* connect */
|
|
if (!fwupd_client_startup (client, cancellable, error))
|
|
return FALSE;
|
|
|
|
/* open file */
|
|
fd = open (metadata_fn, O_RDONLY);
|
|
if (fd < 0) {
|
|
g_set_error (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"failed to open %s",
|
|
metadata_fn);
|
|
return FALSE;
|
|
}
|
|
fd_sig = open (signature_fn, O_RDONLY);
|
|
if (fd_sig < 0) {
|
|
g_set_error (error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"failed to open %s",
|
|
signature_fn);
|
|
return FALSE;
|
|
}
|
|
|
|
/* set out of band file descriptor */
|
|
fd_list = g_unix_fd_list_new ();
|
|
g_unix_fd_list_append (fd_list, fd, NULL);
|
|
g_unix_fd_list_append (fd_list, fd_sig, NULL);
|
|
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);
|
|
close (fd_sig);
|
|
|
|
/* call into daemon */
|
|
body = g_variant_new ("(hh)", fd, fd_sig);
|
|
g_dbus_message_set_body (request, body);
|
|
helper = fwupd_client_helper_new ();
|
|
g_dbus_connection_send_message_with_reply (priv->conn,
|
|
request,
|
|
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
|
|
-1,
|
|
NULL,
|
|
cancellable,
|
|
fwupd_client_send_message_cb,
|
|
helper);
|
|
g_main_loop_run (helper->loop);
|
|
if (!helper->ret) {
|
|
g_propagate_error (error, helper->error);
|
|
helper->error = NULL;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_get_property:
|
|
**/
|
|
static void
|
|
fwupd_client_get_property (GObject *object, guint prop_id,
|
|
GValue *value, GParamSpec *pspec)
|
|
{
|
|
FwupdClient *client = FWUPD_CLIENT (object);
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
|
|
switch (prop_id) {
|
|
case PROP_STATUS:
|
|
g_value_set_uint (value, priv->status);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_set_property:
|
|
**/
|
|
static void
|
|
fwupd_client_set_property (GObject *object, guint prop_id,
|
|
const GValue *value, GParamSpec *pspec)
|
|
{
|
|
FwupdClient *client = FWUPD_CLIENT (object);
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
|
|
switch (prop_id) {
|
|
case PROP_STATUS:
|
|
priv->status = g_value_get_uint (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_class_init:
|
|
**/
|
|
static void
|
|
fwupd_client_class_init (FwupdClientClass *klass)
|
|
{
|
|
GParamSpec *pspec;
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
object_class->finalize = fwupd_client_finalize;
|
|
object_class->get_property = fwupd_client_get_property;
|
|
object_class->set_property = fwupd_client_set_property;
|
|
|
|
/**
|
|
* AsStore::changed:
|
|
* @client: the #FwupdClient instance that emitted the signal
|
|
*
|
|
* The ::changed signal is emitted when the daemon internal has
|
|
* changed, for instance when a device has been added or removed.
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
signals [SIGNAL_CHANGED] =
|
|
g_signal_new ("changed",
|
|
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (FwupdClientClass, changed),
|
|
NULL, NULL, g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
/**
|
|
* AsStore::state-changed:
|
|
* @client: the #FwupdClient instance that emitted the signal
|
|
* @status: the #FwupdStatus
|
|
*
|
|
* The ::state-changed signal is emitted when the daemon status has
|
|
* changed, e.g. going from %FWUPD_STATUS_IDLE to %FWUPD_STATUS_DEVICE_WRITE.
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
signals [SIGNAL_STATUS_CHANGED] =
|
|
g_signal_new ("status-changed",
|
|
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (FwupdClientClass, status_changed),
|
|
NULL, NULL, g_cclosure_marshal_VOID__UINT,
|
|
G_TYPE_NONE, 1, G_TYPE_UINT);
|
|
|
|
/**
|
|
* FwupdClient:status:
|
|
*/
|
|
pspec = g_param_spec_uint ("status", NULL, NULL,
|
|
0, FWUPD_STATUS_LAST, FWUPD_STATUS_UNKNOWN,
|
|
G_PARAM_READWRITE);
|
|
g_object_class_install_property (object_class, PROP_STATUS, pspec);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_init:
|
|
**/
|
|
static void
|
|
fwupd_client_init (FwupdClient *client)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_finalize:
|
|
**/
|
|
static void
|
|
fwupd_client_finalize (GObject *object)
|
|
{
|
|
FwupdClient *client = FWUPD_CLIENT (object);
|
|
FwupdClientPrivate *priv = GET_PRIVATE (client);
|
|
|
|
if (priv->conn != NULL)
|
|
g_object_unref (priv->conn);
|
|
if (priv->proxy != NULL)
|
|
g_object_unref (priv->proxy);
|
|
|
|
G_OBJECT_CLASS (fwupd_client_parent_class)->finalize (object);
|
|
}
|
|
|
|
/**
|
|
* fwupd_client_new:
|
|
*
|
|
* Creates a new client.
|
|
*
|
|
* Returns: a new #FwupdClient
|
|
*
|
|
* Since: 0.7.0
|
|
**/
|
|
FwupdClient *
|
|
fwupd_client_new (void)
|
|
{
|
|
FwupdClient *client;
|
|
client = g_object_new (FWUPD_TYPE_CLIENT, NULL);
|
|
return FWUPD_CLIENT (client);
|
|
}
|