From 8bbfdf49a8bb21138da23d3f844fa99a1909a668 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 26 Feb 2015 22:28:09 +0000 Subject: [PATCH] Flesh out the provider interface and allow offline updates --- po/POTFILES.in | 1 + src/Makefile.am | 4 + src/fu-common.h | 3 + src/fu-debug.c | 210 ++++++++++++++++++++++++++++++++++ src/fu-debug.h | 32 ++++++ src/fu-main.c | 116 ++++++++++++++++--- src/fu-provider-uefi.c | 56 +++++---- src/fu-provider-uefi.h | 18 +-- src/fu-provider.c | 135 ++++++++++++++++++++++ src/fu-provider.h | 81 +++++++++++++ src/fu-util.c | 76 ++++++++++-- src/org.freedesktop.fwupd.xml | 8 +- 12 files changed, 672 insertions(+), 68 deletions(-) create mode 100644 src/fu-debug.c create mode 100644 src/fu-debug.h create mode 100644 src/fu-provider.c create mode 100644 src/fu-provider.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 5f1edc3fe..7312a5e00 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,3 +1,4 @@ policy/org.freedesktop.fwupd.policy.in +src/fu-debug.c src/fu-main.c src/fu-util.c diff --git a/src/Makefile.am b/src/Makefile.am index 21df31d5c..2649c0351 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,8 +57,12 @@ libexec_PROGRAMS = \ fwupd_SOURCES = \ fu-cleanup.h \ fu-common.h \ + fu-debug.c \ + fu-debug.h \ fu-device.c \ fu-device.h \ + fu-provider.c \ + fu-provider.h \ fu-provider-uefi.c \ fu-provider-uefi.h \ fu-resources.c \ diff --git a/src/fu-common.h b/src/fu-common.h index 449ec1bec..9f327981a 100644 --- a/src/fu-common.h +++ b/src/fu-common.h @@ -26,4 +26,7 @@ #define FWUPD_DBUS_SERVICE "org.freedesktop.fwupd" #define FWUPD_DBUS_INTERFACE "org.freedesktop.fwupd" +#define FU_ERROR 1 +#define FU_ERROR_INTERNAL 0 + #endif /* __FU_COMMON_H */ diff --git a/src/fu-debug.c b/src/fu-debug.c new file mode 100644 index 000000000..f13856a3f --- /dev/null +++ b/src/fu-debug.c @@ -0,0 +1,210 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2010-2015 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include + +static gboolean _verbose = FALSE; +static gboolean _console = FALSE; + +/** + * fu_debug_is_verbose: + **/ +gboolean +fu_debug_is_verbose (void) +{ + /* local first */ + if (_verbose) + return TRUE; + + /* fall back to env variable */ + if (g_getenv ("VERBOSE") != NULL) + return TRUE; + return FALSE; +} + + +/** + * fu_debug_ignore_cb: + **/ +static void +fu_debug_ignore_cb (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + /* syslog */ + switch (log_level) { + case G_LOG_LEVEL_INFO: + g_print ("%s\n", message); + case G_LOG_LEVEL_CRITICAL: + case G_LOG_LEVEL_ERROR: + case G_LOG_LEVEL_WARNING: + g_print ("%s\n", message); + break; + default: + break; + } +} + +/** + * fu_debug_handler_cb: + **/ +static void +fu_debug_handler_cb (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + gchar str_time[255]; + time_t the_time; + + /* syslog */ + switch (log_level) { + case G_LOG_LEVEL_INFO: + g_print ("%s\n", message); + case G_LOG_LEVEL_CRITICAL: + case G_LOG_LEVEL_ERROR: + case G_LOG_LEVEL_WARNING: + g_print ("%s\n", message); + break; + default: + break; + } + + /* time header */ + time (&the_time); + strftime (str_time, 254, "%H:%M:%S", localtime (&the_time)); + + /* no color please, we're British */ + if (!_console) { + if (log_level == G_LOG_LEVEL_DEBUG) { + g_print ("%s\t%s\n", + str_time, message); + } else { + g_print ("***\n%s\t%s\n***\n", + str_time, message); + } + return; + } + + /* critical is also in red */ + if (log_level == G_LOG_LEVEL_CRITICAL || + log_level == G_LOG_LEVEL_ERROR) { + g_print ("%c[%dm%s\t", 0x1B, 32, str_time); + g_print ("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0); + } else { + /* debug in blue */ + g_print ("%c[%dm%s\t", 0x1B, 32, str_time); + g_print ("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0); + } +} + +/** + * fu_debug_pre_parse_hook: + */ +static gboolean +fu_debug_pre_parse_hook (GOptionContext *context, + GOptionGroup *group, + gpointer data, + GError **error) +{ + const GOptionEntry main_entries[] = { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &_verbose, + /* TRANSLATORS: turn on all debugging */ + N_("Show debugging information for all files"), NULL }, + { NULL} + }; + + /* add main entry */ + g_option_context_add_main_entries (context, main_entries, NULL); + return TRUE; +} + +/** + * fu_debug_destroy: + */ +void +fu_debug_destroy (void) +{ +} + +/** + * fu_debug_setup: + */ +void +fu_debug_setup (gboolean enabled) +{ + if (enabled) { + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | + G_LOG_LEVEL_CRITICAL); + g_log_set_handler (G_LOG_DOMAIN, + G_LOG_LEVEL_ERROR | + G_LOG_LEVEL_CRITICAL | + G_LOG_LEVEL_DEBUG | + G_LOG_LEVEL_WARNING, + fu_debug_handler_cb, NULL); + } else { + /* hide all debugging */ + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + fu_debug_ignore_cb, NULL); + } + + /* are we on an actual TTY? */ + _console = (isatty (fileno (stdout)) == 1); +} + +/** + * fu_debug_post_parse_hook: + */ +static gboolean +fu_debug_post_parse_hook (GOptionContext *context, + GOptionGroup *group, + gpointer data, + GError **error) +{ + /* verbose? */ + fu_debug_setup (_verbose); + g_debug ("Verbose debugging %s (on console %i)", + _verbose ? "enabled" : "disabled", _console); + return TRUE; +} + +/** + * fu_debug_get_option_group: + */ +GOptionGroup * +fu_debug_get_option_group (void) +{ + GOptionGroup *group; + group = g_option_group_new ("debug", + _("Debugging Options"), + _("Show debugging options"), + NULL, NULL); + g_option_group_set_parse_hooks (group, + fu_debug_pre_parse_hook, + fu_debug_post_parse_hook); + return group; +} diff --git a/src/fu-debug.h b/src/fu-debug.h new file mode 100644 index 000000000..9bcea359e --- /dev/null +++ b/src/fu-debug.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2010-2011 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __CD_DEBUG_H__ +#define __CD_DEBUG_H__ + +#include + +gboolean fu_debug_is_verbose (void); +GOptionGroup *fu_debug_get_option_group (void); +void fu_debug_setup (gboolean enabled); +void fu_debug_destroy (void); + +#endif /* __CD_DEBUG_H__ */ diff --git a/src/fu-main.c b/src/fu-main.c index 24692c05e..b55ac2512 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -29,19 +29,17 @@ #include "fu-cleanup.h" #include "fu-common.h" +#include "fu-debug.h" #include "fu-device.h" #include "fu-provider-uefi.h" #include "fu-resources.h" -#define FU_ERROR 1 -#define FU_ERROR_INTERNAL 0 - typedef struct { GDBusConnection *connection; GDBusNodeInfo *introspection_daemon; GMainLoop *loop; GPtrArray *devices; - FuProviderUefi *provider_uefi; + GPtrArray *providers; } FuMainPrivate; /** @@ -62,6 +60,23 @@ fu_main_get_device_list_as_strv (FuMainPrivate *priv) return val; } +/** + * fu_main_get_device_by_id: + **/ +static FuDevice * +fu_main_get_device_by_id (FuMainPrivate *priv, const gchar *id) +{ + FuDevice *device_tmp; + guint i; + + for (i = 0; i < priv->devices->len; i++) { + device_tmp = g_ptr_array_index (priv->devices, i); + if (g_strcmp0 (fu_device_get_id (device_tmp), id) == 0) + return device_tmp; + } + return NULL; +} + /** * fu_main_daemon_method_call: **/ @@ -74,6 +89,8 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, FuMainPrivate *priv = (FuMainPrivate *) user_data; GVariant *val; + g_debug ("Called %s()", method_name); + /* return 'as' */ if (g_strcmp0 (method_name, "GetDevices") == 0) { _cleanup_strv_free_ gchar **devices = NULL; @@ -83,6 +100,55 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, return; } + /* return '' */ + if (g_strcmp0 (method_name, "UpdateOffline") == 0) { + GDBusMessage *message; + GUnixFDList *fd_list; + FuDevice *device; + const gchar *id = NULL; + gint32 fd_handle = 0; + gint fd; + _cleanup_error_free_ GError *error = NULL; + + /* check the id exists */ + g_variant_get (parameters, "(&sh)", &id, &fd_handle); + device = fu_main_get_device_by_id (priv, id); + if (device == NULL) { + g_dbus_method_invocation_return_error (invocation, + FU_ERROR, + FU_ERROR_INTERNAL, + "no such ID %s", + id); + return; + } + + /* get the fd */ + message = g_dbus_method_invocation_get_message (invocation); + fd_list = g_dbus_message_get_unix_fd_list (message); + if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) { + g_dbus_method_invocation_return_error (invocation, + FU_ERROR, + FU_ERROR_INTERNAL, + "invalid handle"); + return; + } + fd = g_unix_fd_list_get (fd_list, fd_handle, &error); + if (fd < 0) { + g_dbus_method_invocation_return_gerror (invocation, + error); + return; + } + + /* TODO: run the correct provider that can handle this */ +// if (!fu_provider_update_offline (provider, device, fd, &error)) { +// g_dbus_method_invocation_return_gerror (invocation, +// error); +// return; +// } + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + /* we suck */ g_dbus_method_invocation_return_error (invocation, FU_ERROR, @@ -148,8 +214,16 @@ fu_main_on_name_acquired_cb (GDBusConnection *connection, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; - fu_provider_uefi_coldplug (priv->provider_uefi); + FuProvider *provider; + guint i; + g_debug ("FuMain: acquired name: %s", name); + for (i = 0; i < priv->providers->len; i++) { + _cleanup_error_free_ GError *error = NULL; + provider = g_ptr_array_index (priv->providers, i); + if (!fu_provider_coldplug (FU_PROVIDER (provider), &error)) + g_warning ("Failed to coldplug: %s", error->message); + } } /** @@ -202,7 +276,7 @@ fu_main_load_introspection (const gchar *filename, GError **error) * cd_main_provider_device_added_cb: **/ static void -cd_main_provider_device_added_cb (FuProviderUefi *provider_uefi, +cd_main_provider_device_added_cb (FuProvider *provider, FuDevice *device, gpointer user_data) { @@ -214,7 +288,7 @@ cd_main_provider_device_added_cb (FuProviderUefi *provider_uefi, * cd_main_provider_device_removed_cb: **/ static void -cd_main_provider_device_removed_cb (FuProviderUefi *provider_uefi, +cd_main_provider_device_removed_cb (FuProvider *provider, FuDevice *device, gpointer user_data) { @@ -222,6 +296,21 @@ cd_main_provider_device_removed_cb (FuProviderUefi *provider_uefi, g_ptr_array_remove (priv->devices, g_object_ref (device)); } +/** + * fu_main_add_provider: + **/ +static void +fu_main_add_provider (FuMainPrivate *priv, FuProvider *provider) +{ + g_signal_connect (provider, "device-added", + G_CALLBACK (cd_main_provider_device_added_cb), + priv); + g_signal_connect (provider, "device-removed", + G_CALLBACK (cd_main_provider_device_removed_cb), + priv); + g_ptr_array_add (priv->providers, provider); +} + /** * main: **/ @@ -256,6 +345,7 @@ main (int argc, char *argv[]) g_set_application_name (_("Firmware Update")); context = g_option_context_new (NULL); g_option_context_add_main_entries (context, options, NULL); + g_option_context_add_group (context, fu_debug_get_option_group ()); g_option_context_set_summary (context, _("Firmware Update D-Bus Service")); ret = g_option_context_parse (context, &argc, &argv, &error); if (!ret) { @@ -268,13 +358,10 @@ main (int argc, char *argv[]) priv = g_new0 (FuMainPrivate, 1); priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->loop = g_main_loop_new (NULL, FALSE); - priv->provider_uefi = fu_provider_uefi_new (); - g_signal_connect (priv->provider_uefi, "device-added", - G_CALLBACK (cd_main_provider_device_added_cb), - priv); - g_signal_connect (priv->provider_uefi, "device-removed", - G_CALLBACK (cd_main_provider_device_removed_cb), - priv); + + /* add providers */ + priv->providers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + fu_main_add_provider (priv, fu_provider_uefi_new ()); /* load introspection from file */ priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml", @@ -319,6 +406,7 @@ out: g_object_unref (priv->connection); if (priv->introspection_daemon != NULL) g_dbus_node_info_unref (priv->introspection_daemon); + g_ptr_array_unref (priv->providers); g_ptr_array_unref (priv->devices); g_free (priv); } diff --git a/src/fu-provider-uefi.c b/src/fu-provider-uefi.c index f57fef2c5..82efeb600 100644 --- a/src/fu-provider-uefi.c +++ b/src/fu-provider-uefi.c @@ -40,15 +40,7 @@ struct _FuProviderUefiPrivate GPtrArray *array_devices; }; -enum { - SIGNAL_SENSOR_ADDED, - SIGNAL_SENSOR_REMOVED, - SIGNAL_LAST -}; - -static guint signals[SIGNAL_LAST] = { 0 }; - -G_DEFINE_TYPE (FuProviderUefi, fu_provider_uefi, G_TYPE_OBJECT) +G_DEFINE_TYPE (FuProviderUefi, fu_provider_uefi, FU_TYPE_PROVIDER) /** * fu_provider_uefi_get_by_id: @@ -72,19 +64,34 @@ fu_provider_uefi_get_by_id (FuProviderUefi *provider_uefi, return device; } +/** + * fu_provider_uefi_update_offline: + **/ +static gboolean +fu_provider_uefi_update_offline (FuProvider *provider, + FuDevice *device, + gint fd, + GError **error) +{ + //FIXME + return TRUE; +} + /** * fu_provider_uefi_coldplug: **/ -void -fu_provider_uefi_coldplug (FuProviderUefi *provider_uefi) +static gboolean +fu_provider_uefi_coldplug (FuProvider *provider, GError **error) { +// FuProviderUefi *provider_uefi = FU_PROVIDER_UEFI (provider); _cleanup_object_unref_ FuDevice *dev = NULL; //FIXME g_debug ("Adding fake UEFI device"); dev = fu_device_new (); fu_device_set_id (dev, "819b858e-c52c-402f-80e1-5b311b6c1959"); - g_signal_emit (provider_uefi, signals[SIGNAL_SENSOR_ADDED], 0, dev); + fu_provider_emit_added (provider, dev); + return TRUE; } /** @@ -93,20 +100,12 @@ fu_provider_uefi_coldplug (FuProviderUefi *provider_uefi) static void fu_provider_uefi_class_init (FuProviderUefiClass *klass) { + FuProviderClass *provider_class = FU_PROVIDER_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); + + provider_class->coldplug = fu_provider_uefi_coldplug; + provider_class->update_offline = fu_provider_uefi_update_offline; object_class->finalize = fu_provider_uefi_finalize; - signals[SIGNAL_SENSOR_ADDED] = - g_signal_new ("device-added", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (FuProviderUefiClass, device_added), - NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, FU_TYPE_DEVICE); - signals[SIGNAL_SENSOR_REMOVED] = - g_signal_new ("device-removed", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (FuProviderUefiClass, device_removed), - NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, FU_TYPE_DEVICE); g_type_class_add_private (klass, sizeof (FuProviderUefiPrivate)); } @@ -138,11 +137,10 @@ fu_provider_uefi_finalize (GObject *object) /** * fu_provider_uefi_new: **/ -FuProviderUefi * +FuProvider * fu_provider_uefi_new (void) { - FuProviderUefi *provider_uefi; - provider_uefi = g_object_new (FU_TYPE_PROVIDER_UEFI, NULL); - return FU_PROVIDER_UEFI (provider_uefi); + FuProviderUefi *provider; + provider = g_object_new (FU_TYPE_PROVIDER_UEFI, NULL); + return FU_PROVIDER (provider); } - diff --git a/src/fu-provider-uefi.h b/src/fu-provider-uefi.h index e45004491..8d4467a0f 100644 --- a/src/fu-provider-uefi.h +++ b/src/fu-provider-uefi.h @@ -25,16 +25,15 @@ #include #include "fu-device.h" -#include "fu-provider-uefi.h" +#include "fu-provider.h" G_BEGIN_DECLS #define FU_TYPE_PROVIDER_UEFI (fu_provider_uefi_get_type ()) #define FU_PROVIDER_UEFI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FU_TYPE_PROVIDER_UEFI, FuProviderUefi)) -#define FU_PROVIDER_UEFI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), FU_TYPE_PROVIDER_UEFI, FuProviderUefiClass)) +//#define FU_PROVIDER_UEFI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), FU_TYPE_PROVIDER_UEFI, FuProviderUefiClass)) #define FU_IS_PROVIDER_UEFI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FU_TYPE_PROVIDER_UEFI)) -#define FU_IS_PROVIDER_UEFI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), FU_TYPE_PROVIDER_UEFI)) -#define FU_PROVIDER_UEFI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), FU_TYPE_PROVIDER_UEFI, FuProviderUefiClass)) +//#define FU_IS_PROVIDER_UEFI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), FU_TYPE_PROVIDER_UEFI)) typedef struct _FuProviderUefiPrivate FuProviderUefiPrivate; typedef struct _FuProviderUefi FuProviderUefi; @@ -42,22 +41,17 @@ typedef struct _FuProviderUefiClass FuProviderUefiClass; struct _FuProviderUefi { - GObject parent; + FuProvider parent; FuProviderUefiPrivate *priv; }; struct _FuProviderUefiClass { - GObjectClass parent_class; - void (* device_added) (FuProviderUefi *provider_uefi, - FuDevice *device); - void (* device_removed) (FuProviderUefi *provider_uefi, - FuDevice *device); + FuProviderClass parent_class; }; GType fu_provider_uefi_get_type (void); -FuProviderUefi *fu_provider_uefi_new (void); -void fu_provider_uefi_coldplug (FuProviderUefi *provider_uefi); +FuProvider *fu_provider_uefi_new (void); G_END_DECLS diff --git a/src/fu-provider.c b/src/fu-provider.c new file mode 100644 index 000000000..8ffef05e0 --- /dev/null +++ b/src/fu-provider.c @@ -0,0 +1,135 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2015 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include + +#include "fu-cleanup.h" +#include "fu-common.h" +#include "fu-device.h" +#include "fu-provider-uefi.h" + +static void fu_provider_finalize (GObject *object); + +#define FU_PROVIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FU_TYPE_PROVIDER, FuProviderPrivate)) + +enum { + SIGNAL_DEVICE_ADDED, + SIGNAL_DEVICE_REMOVED, + SIGNAL_LAST +}; + +static guint signals[SIGNAL_LAST] = { 0 }; + +G_DEFINE_TYPE (FuProvider, fu_provider, G_TYPE_OBJECT) + +/** + * fu_provider_coldplug: + **/ +gboolean +fu_provider_coldplug (FuProvider *provider, GError **error) +{ + FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); + if (klass->coldplug != NULL) + return klass->coldplug (provider, error); + return TRUE; +} + +/** + * fu_provider_update_offline: + **/ +gboolean +fu_provider_update_offline (FuProvider *provider, + FuDevice *device, + gint fd, + GError **error) +{ + FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); + if (klass->update_offline == NULL) { + g_set_error_literal (error, + FU_ERROR, + FU_ERROR_INTERNAL, + "No offline update functionality"); + return FALSE; + } + return klass->update_offline (provider, device, fd, error); +} + +/** + * fu_provider_emit_added: + **/ +void +fu_provider_emit_added (FuProvider *provider, FuDevice *device) +{ + g_debug ("emit added: %s", fu_device_get_id (device)); + g_signal_emit (provider, signals[SIGNAL_DEVICE_ADDED], 0, device); +} + +/** + * fu_provider_emit_removed: + **/ +void +fu_provider_emit_removed (FuProvider *provider, FuDevice *device) +{ + g_debug ("emit removed: %s", fu_device_get_id (device)); + g_signal_emit (provider, signals[SIGNAL_DEVICE_REMOVED], 0, device); +} + +/** + * fu_provider_class_init: + **/ +static void +fu_provider_class_init (FuProviderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_provider_finalize; + signals[SIGNAL_DEVICE_ADDED] = + g_signal_new ("device-added", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuProviderClass, device_added), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, FU_TYPE_DEVICE); + signals[SIGNAL_DEVICE_REMOVED] = + g_signal_new ("device-removed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuProviderClass, device_removed), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, FU_TYPE_DEVICE); +} + +/** + * fu_provider_init: + **/ +static void +fu_provider_init (FuProvider *provider) +{ +} + +/** + * fu_provider_finalize: + **/ +static void +fu_provider_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_provider_parent_class)->finalize (object); +} diff --git a/src/fu-provider.h b/src/fu-provider.h new file mode 100644 index 000000000..41cb688a9 --- /dev/null +++ b/src/fu-provider.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2015 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __FU_PROVIDER_H +#define __FU_PROVIDER_H + +#include + +#include "fu-device.h" +#include "fu-provider.h" + +G_BEGIN_DECLS + +#define FU_TYPE_PROVIDER (fu_provider_get_type ()) +#define FU_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FU_TYPE_PROVIDER, FuProvider)) +#define FU_PROVIDER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), FU_TYPE_PROVIDER, FuProviderClass)) +#define FU_IS_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FU_TYPE_PROVIDER)) +#define FU_IS_PROVIDER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), FU_TYPE_PROVIDER)) +#define FU_PROVIDER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), FU_TYPE_PROVIDER, FuProviderClass)) + +typedef struct _FuProvider FuProvider; +typedef struct _FuProviderClass FuProviderClass; + +struct _FuProvider +{ + GObject parent; +}; + +struct _FuProviderClass +{ + GObjectClass parent_class; + + /* vfunc */ + gboolean (*coldplug) (FuProvider *provider, + GError **error); + gboolean (*update_offline) (FuProvider *provider, + FuDevice *device, + gint fd, + GError **error); + + /* signals */ + void (* device_added) (FuProvider *provider, + FuDevice *device); + void (* device_removed) (FuProvider *provider, + FuDevice *device); +}; + +GType fu_provider_get_type (void); +void fu_provider_emit_added (FuProvider *provider, + FuDevice *device); +void fu_provider_emit_removed (FuProvider *provider, + FuDevice *device); +gboolean fu_provider_coldplug (FuProvider *provider, + GError **error); +gboolean fu_provider_update_offline (FuProvider *provider, + FuDevice *device, + gint fd, + GError **error); + +G_END_DECLS + +#endif /* __FU_PROVIDER_H */ + diff --git a/src/fu-util.c b/src/fu-util.c index ad4daf72f..aaebc99e2 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -21,11 +21,13 @@ #include "config.h" -#include +#include #include +#include +#include #include -#include #include +#include #include "fu-cleanup.h" #include "fu-common.h" @@ -194,7 +196,7 @@ fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) _cleanup_object_unref_ GDBusConnection *conn = NULL; _cleanup_object_unref_ GDBusProxy *proxy = NULL; _cleanup_variant_unref_ GVariant *val = NULL; - const gchar **guids = NULL; + const gchar **ids = NULL; guint i; conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); @@ -219,12 +221,12 @@ fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) error); if (val == NULL) return FALSE; - g_variant_get (val, "(^a&s)", &guids); - g_assert (guids != NULL); - if (guids[0] == NULL) + g_variant_get (val, "(^a&s)", &ids); + g_assert (ids != NULL); + if (ids[0] == NULL) g_print ("No hardware detected with firmware update capaility\n"); - for (i = 0; guids[i] != NULL; i++) - g_print ("%i: %s\n", i, guids[i]); + for (i = 0; ids[i] != NULL; i++) + g_print ("%i: %s\n", i, ids[i]); return TRUE; } @@ -234,7 +236,63 @@ fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) static gboolean fu_util_update_offline (FuUtilPrivate *priv, gchar **values, GError **error) { - //FIXME + GVariant *body; + gint retval; + gint fd; + _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; + + if (g_strv_length (values) != 2) { + g_set_error_literal (error, + FU_ERROR, + FU_ERROR_INTERNAL, + "Invalid arguments: expected 'id' 'filename'"); + return FALSE; + } + + conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (conn == NULL) + return FALSE; + + /* open file */ + fd = open (values[1], O_RDONLY); + if (fd < 0) { + g_set_error (error, + FU_ERROR, + FU_ERROR_INTERNAL, + "failed to open %s", + values[1]); + 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, + "UpdateOffline"); + g_dbus_message_set_unix_fd_list (request, fd_list); + + /* g_unix_fd_list_append did a dup() already */ + close (fd); + + /* send message */ + body = g_variant_new ("(sh)", values[0], fd); + 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) + return FALSE; + return TRUE; } diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 20c45fa24..81a0d9506 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -31,10 +31,10 @@ - + - An array of GUIDs. + An array of IDs. @@ -49,10 +49,10 @@ - + - A GUID of the hardware to update. + An ID, typically a GUID of the hardware to update.