[gnome-packagekit] Enhance GpkFirmware by only asking to replug hardware (rather than reboot) if it is hotpluggable
- From: Richard Hughes <rhughes src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-packagekit] Enhance GpkFirmware by only asking to replug hardware (rather than reboot) if it is hotpluggable
- Date: Wed, 19 Aug 2009 11:52:18 +0000 (UTC)
commit 7becfa208eb03f13498402a565e33983d4cee9ef
Author: Richard Hughes <richard hughsie com>
Date: Wed Aug 19 12:09:35 2009 +0100
Enhance GpkFirmware by only asking to replug hardware (rather than reboot) if it is hotpluggable
This functionality also requires GUdev to work correctly.
src/gpk-firmware.c | 363 ++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 310 insertions(+), 53 deletions(-)
---
diff --git a/src/gpk-firmware.c b/src/gpk-firmware.c
index 0475d3d..5f69792 100644
--- a/src/gpk-firmware.c
+++ b/src/gpk-firmware.c
@@ -34,10 +34,14 @@
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <glib/gi18n.h>
+#include <gio/gio.h>
#include <gtk/gtk.h>
#include <gconf/gconf-client.h>
#include <libnotify/notify.h>
#include <packagekit-glib/packagekit.h>
+#ifdef GPK_BUILD_GUDEV
+#include <gudev/gudev.h>
+#endif
#include "egg-debug.h"
#include "egg-string.h"
@@ -63,9 +67,92 @@ struct GpkFirmwarePrivate
EggConsoleKit *consolekit;
};
+typedef enum {
+ GPK_FIRMWARE_SUBSYSTEM_USB,
+ GPK_FIRMWARE_SUBSYSTEM_PCI,
+ GPK_FIRMWARE_SUBSYSTEM_UNKNOWN
+} GpkFirmwareSubsystem;
+
+typedef struct {
+ gchar *filename;
+ gchar *model;
+ GpkFirmwareSubsystem subsystem;
+} GpkFirmwareRequest;
+
G_DEFINE_TYPE (GpkFirmware, gpk_firmware, G_TYPE_OBJECT)
/**
+ * gpk_firmware_subsystem_can_replug:
+ **/
+static gboolean
+gpk_firmware_subsystem_can_replug (GpkFirmwareSubsystem subsystem)
+{
+ if (subsystem == GPK_FIRMWARE_SUBSYSTEM_USB)
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * gpk_firmware_request_new:
+ **/
+static GpkFirmwareRequest *
+gpk_firmware_request_new (const gchar *filename, const gchar *sysfs_path)
+{
+ GpkFirmwareRequest *req;
+#ifdef GPK_BUILD_GUDEV
+ GUdevDevice *device;
+ GUdevClient *client;
+ const gchar *subsystem;
+ const gchar *model;
+#endif
+
+ req = g_new0 (GpkFirmwareRequest, 1);
+ req->filename = g_strdup (filename);
+ req->subsystem = GPK_FIRMWARE_SUBSYSTEM_UNKNOWN;
+#ifdef GPK_BUILD_GUDEV
+
+ /* get all subsystems */
+ client = g_udev_client_new (NULL);
+ device = g_udev_client_query_by_sysfs_path (client, sysfs_path);
+ if (device == NULL)
+ goto out;
+
+ /* find subsystem, which will affect if we have to replug, or reboot */
+ subsystem = g_udev_device_get_subsystem (device);
+ if (g_strcmp0 (subsystem, "usb") == 0) {
+ req->subsystem = GPK_FIRMWARE_SUBSYSTEM_USB;
+ } else if (g_strcmp0 (subsystem, "pci") == 0) {
+ req->subsystem = GPK_FIRMWARE_SUBSYSTEM_PCI;
+ } else {
+ egg_warning ("subsystem unrecognised: %s", subsystem);
+ }
+
+ /* get model, so we can show something sensible */
+ model = g_udev_device_get_property (device, "ID_MODEL");
+ if (model != NULL && model[0] != '\0') {
+ req->model = g_strdup (model);
+ /* replace invalid chars */
+ g_strdelimit (req->model, "_", ' ');
+ }
+out:
+ g_object_unref (device);
+ g_object_unref (client);
+#endif
+ return req;
+}
+
+/**
+ * gpk_firmware_request_free:
+ **/
+static void
+gpk_firmware_request_free (GpkFirmwareRequest *req)
+{
+ g_free (req->filename);
+ g_free (req->model);
+ g_free (req);
+}
+
+/**
* gpk_firmware_install_file:
**/
static gboolean
@@ -187,23 +274,24 @@ gpk_firmware_timeout_cb (gpointer data)
{
guint i;
gboolean ret;
- const gchar *filename;
- const gchar *message;
+ GString *string;
GpkFirmware *firmware = GPK_FIRMWARE (data);
NotifyNotification *notification;
GPtrArray *array;
GError *error = NULL;
PkPackageObj *obj = NULL;
+ const GpkFirmwareRequest *req;
+ gboolean has_data = FALSE;
- /* debug so we can catch polling */
- egg_debug ("polling check");
+ /* message string */
+ string = g_string_new ("");
/* try to find each firmware file in an available package */
array = firmware->priv->array_requested;
for (i=0; i<array->len; i++) {
- filename = g_ptr_array_index (array, i);
+ req = g_ptr_array_index (array, i);
/* save to new array if we found one package for this file */
- obj = gpk_firmware_check_available (firmware, filename);
+ obj = gpk_firmware_check_available (firmware, req->filename);
if (obj != NULL) {
pk_obj_list_add (PK_OBJ_LIST (firmware->priv->packages_found), obj);
pk_package_obj_free (obj);
@@ -219,10 +307,31 @@ gpk_firmware_timeout_cb (gpointer data)
/* check we don't want the same package more than once */
pk_obj_list_remove_duplicate (PK_OBJ_LIST (firmware->priv->packages_found));
+ /* have we got any models to list */
+ for (i=0; i<array->len; i++) {
+ req = g_ptr_array_index (array, i);
+ if (req->model != NULL) {
+ has_data = TRUE;
+ break;
+ }
+ }
+
/* TRANSLATORS: we need another package to keep udev quiet */
- message = _("Additional firmware is required to make hardware in this computer function correctly.");
+ g_string_append (string, _("Additional firmware is required to make hardware in this computer function correctly."));
+
+ /* sdd what information we have */
+ if (has_data) {
+ g_string_append (string, "\n");
+ for (i=0; i<array->len; i++) {
+ req = g_ptr_array_index (array, i);
+ if (req->model != NULL)
+ g_string_append_printf (string, "\nâ?¢ %s", req->model);
+ }
+ g_string_append (string, "\n");
+ }
+
/* TRANSLATORS: title of libnotify bubble */
- notification = notify_notification_new (_("Additional firmware required"), message, "help-browser", NULL);
+ notification = notify_notification_new (_("Additional firmware required"), string->str, "help-browser", NULL);
notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER);
notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
notify_notification_add_action (notification, "install-firmware",
@@ -237,6 +346,7 @@ gpk_firmware_timeout_cb (gpointer data)
}
out:
+ g_string_free (string, TRUE);
/* never repeat */
return FALSE;
}
@@ -250,9 +360,9 @@ gpk_firmware_remove_banned (GpkFirmware *firmware, GPtrArray *array)
{
gchar *banned_str;
gchar **banned = NULL;
- gchar *filename;
guint i, j;
gboolean ret;
+ GpkFirmwareRequest *req;
/* get from gconf */
banned_str = gconf_client_get_string (firmware->priv->gconf_client, GPK_CONF_BANNED_FIRMWARE, NULL);
@@ -272,12 +382,12 @@ gpk_firmware_remove_banned (GpkFirmware *firmware, GPtrArray *array)
/* remove any banned pattern matches */
for (i=0; i<array->len; i++) {
- filename = g_ptr_array_index (array, i);
+ req = g_ptr_array_index (array, i);
for (j=0; banned[j] != NULL; j++) {
- ret = g_pattern_match_simple (banned[j], filename);
+ ret = g_pattern_match_simple (banned[j], req->filename);
if (ret) {
- egg_debug ("match %s for %s, removing", banned[j], filename);
- g_free (filename);
+ egg_debug ("match %s for %s, removing", banned[j], req->filename);
+ gpk_firmware_request_free (req);
g_ptr_array_remove_index_fast (array, i);
}
}
@@ -362,17 +472,80 @@ gpk_firmware_primary_requeue (GpkFirmware *firmware)
}
/**
- * gpk_update_viewer_finished_cb:
+ * gpk_firmware_require_restart:
**/
static void
-gpk_update_viewer_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, GpkFirmware *firmware)
+gpk_firmware_require_restart (GpkFirmware *firmware)
{
+ const gchar *message;
gboolean can_restart = FALSE;
- PkRoleEnum role;
+ gboolean ret;
+ GError *error = NULL;
NotifyNotification *notification;
+
+ /* TRANSLATORS: we need to restart so the new hardware can re-request the firmware */
+ message = _("You will need to restart this computer before the hardware will work correctly.");
+
+ /* TRANSLATORS: title of libnotify bubble */
+ notification = notify_notification_new (_("Additional firmware was installed"), message, "help-browser", NULL);
+ notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER);
+ notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+
+ /* only show the restart button if we can restart */
+ egg_console_kit_can_restart (firmware->priv->consolekit, &can_restart, NULL);
+ if (can_restart) {
+ notify_notification_add_action (notification, "restart-now",
+ /* TRANSLATORS: button label */
+ _("Restart now"), gpk_firmware_libnotify_cb, firmware, NULL);
+ }
+
+ /* show the bubble */
+ ret = notify_notification_show (notification, &error);
+ if (!ret) {
+ egg_warning ("error: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+/**
+ * gpk_firmware_require_replug:
+ **/
+static void
+gpk_firmware_require_replug (GpkFirmware *firmware)
+{
const gchar *message;
gboolean ret;
GError *error = NULL;
+ NotifyNotification *notification;
+
+ /* TRANSLATORS: we need to remove an replug so the new hardware can re-request the firmware */
+ message = _("You will need to remove and then reinsert the hardware before it will work correctly.");
+
+ /* TRANSLATORS: title of libnotify bubble */
+ notification = notify_notification_new (_("Additional firmware was installed"), message, "help-browser", NULL);
+ notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER);
+ notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+
+ /* show the bubble */
+ ret = notify_notification_show (notification, &error);
+ if (!ret) {
+ egg_warning ("error: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+/**
+ * gpk_firmware_finished_cb:
+ **/
+static void
+gpk_firmware_finished_cb (PkClient *client, PkExitEnum exit_enum, guint runtime, GpkFirmware *firmware)
+{
+ PkRoleEnum role;
+ gboolean restart = FALSE;
+ const GpkFirmwareRequest *req;
+ GPtrArray *array;
+ gboolean ret;
+ guint i;
pk_client_get_role (client, &role, NULL, NULL);
egg_debug ("role: %s, exit: %s", pk_role_enum_to_text (role), pk_exit_enum_to_text (exit_enum));
@@ -388,29 +561,120 @@ gpk_update_viewer_finished_cb (PkClient *client, PkExitEnum exit_enum, guint run
/* tell the user we installed okay */
if (exit_enum == PK_EXIT_ENUM_SUCCESS && role == PK_ROLE_ENUM_INSTALL_PACKAGES) {
- /* TRANSLATORS: we need to restart so the new hardware can re-request the firmware */
- message = _("You will need to restart this computer before the hardware will work correctly.");
+ /* go through all the requests, and find the worst type */
+ array = firmware->priv->array_requested;
+ for (i=0; i<array->len; i++) {
+ req = g_ptr_array_index (array, i);
+ ret = gpk_firmware_subsystem_can_replug (req->subsystem);
+ if (!ret) {
+ restart = TRUE;
+ break;
+ }
+ }
- /* TRANSLATORS: title of libnotify bubble */
- notification = notify_notification_new (_("Additional firmware was installed"), message, "help-browser", NULL);
- notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER);
- notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+ /* give the user the correct message */
+ if (restart)
+ gpk_firmware_require_restart (firmware);
+ else
+ gpk_firmware_require_replug (firmware);
+ }
+}
- /* only show the restart button if we can restart */
- egg_console_kit_can_restart (firmware->priv->consolekit, &can_restart, NULL);
- if (can_restart) {
- notify_notification_add_action (notification, "restart-now",
- /* TRANSLATORS: button label */
- _("Restart now"), gpk_firmware_libnotify_cb, firmware, NULL);
- }
+/**
+ * gpk_firmware_get_device:
+ **/
+static gchar *
+gpk_firmware_get_device (GpkFirmware *firmware, const gchar *filename)
+{
+ GFile *file;
+ GFileInfo *info;
+ const gchar *symlink_path;
+ guint len;
+ gchar *syspath = NULL;
+ gchar **split = NULL;
+ GError *error = NULL;
+ gchar *target = NULL;
+ guint i;
- /* show the bubble */
- ret = notify_notification_show (notification, &error);
- if (!ret) {
- egg_warning ("error: %s", error->message);
- g_error_free (error);
- }
+ /* get the file data */
+ file = g_file_new_for_path (filename);
+ info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, G_FILE_QUERY_INFO_NONE, NULL, &error);
+ if (info == NULL) {
+ egg_warning ("Failed to get symlink: %s", error->message);
+ g_error_free (error);
+ goto out;
}
+
+ /* /devices/pci0000:00/0000:00:1d.0/usb5/5-2/firmware/5-2 */
+ symlink_path = g_file_info_get_symlink_target (info);
+ if (symlink_path == NULL) {
+ egg_warning ("failed to get symlink target");
+ goto out;
+ }
+
+ /* prepend sys to make '/sys/devices/pci0000:00/0000:00:1d.0/usb5/5-2/firmware/5-2' */
+ syspath = g_strjoin (NULL, "/sys", symlink_path, NULL);
+
+ /* now find device without the junk */
+ split = g_strsplit (syspath, "/", -1);
+ len = g_strv_length (split);
+
+ /* start with the longest, and try to find a path that exists */
+ for (i=len; i>1; i--) {
+ split[i] = NULL;
+ target = g_strjoinv ("/", split);
+ egg_debug ("testing %s", target);
+ if (g_file_test (target, G_FILE_TEST_EXISTS))
+ goto out;
+ g_free (target);
+ }
+
+ /* ensure we return error if nothing found */
+ target = NULL;
+out:
+ if (info != NULL)
+ g_object_unref (info);
+ g_object_unref (file);
+ g_free (syspath);
+ g_strfreev (split);
+ return target;
+}
+
+/**
+ * gpk_firmware_add_file:
+ **/
+static void
+gpk_firmware_add_file (GpkFirmware *firmware, const gchar *filename_no_path)
+{
+ gchar *filename_path;
+ gchar *missing_path;
+ gchar *sysfs_path;
+ gboolean ret;
+ GpkFirmwareRequest *req;
+
+ /* this is the file we want to load */
+ filename_path = g_build_filename (GPK_FIRMWARE_LOADING_DIR, filename_no_path, NULL);
+
+ /* file already exists */
+ ret = g_file_test (filename_path, G_FILE_TEST_EXISTS);
+ if (ret)
+ goto out;
+
+ /* this is the file that udev created for us */
+ missing_path = g_build_filename (GPK_FIRMWARE_MISSING_DIR, filename_no_path, NULL);
+ egg_debug ("filename=%s -> %s", missing_path, filename_path);
+
+ /* get symlink target */
+ sysfs_path = gpk_firmware_get_device (firmware, missing_path);
+ if (sysfs_path == NULL)
+ goto out;
+
+ /* create new request object */
+ req = gpk_firmware_request_new (filename_path, sysfs_path);
+ g_ptr_array_add (firmware->priv->array_requested, req);
+out:
+ g_free (filename_path);
+ g_free (sysfs_path);
}
/**
@@ -437,9 +701,9 @@ gpk_firmware_init (GpkFirmware *firmware)
GDir *dir;
const gchar *filename;
gchar *filename_decoded;
- gchar *filename_path;
guint i;
GPtrArray *array;
+ const GpkFirmwareRequest *req;
firmware->priv = GPK_FIRMWARE_GET_PRIVATE (firmware);
firmware->priv->packages_found = pk_package_list_new ();
@@ -452,7 +716,7 @@ gpk_firmware_init (GpkFirmware *firmware)
g_signal_connect (firmware->priv->client_primary, "error-code",
G_CALLBACK (gpk_firmware_error_code_cb), firmware);
g_signal_connect (firmware->priv->client_primary, "finished",
- G_CALLBACK (gpk_update_viewer_finished_cb), firmware);
+ G_CALLBACK (gpk_firmware_finished_cb), firmware);
/* should we check and show the user */
ret = gconf_client_get_bool (firmware->priv->gconf_client, GPK_CONF_ENABLE_CHECK_FIRMWARE, NULL);
@@ -471,39 +735,32 @@ gpk_firmware_init (GpkFirmware *firmware)
/* find all the firmware requests */
filename = g_dir_read_name (dir);
- array = firmware->priv->array_requested;
while (filename != NULL) {
- /* decode udev text */
filename_decoded = gpk_firmware_udev_text_decode (filename);
- filename_path = g_build_filename (GPK_FIRMWARE_LOADING_DIR, filename_decoded, NULL);
- egg_debug ("filename=%s -> %s", filename, filename_path);
-
- /* file already exists */
- ret = g_file_test (filename_path, G_FILE_TEST_EXISTS);
- if (!ret)
- g_ptr_array_add (array, g_strdup (filename_path));
-
+ gpk_firmware_add_file (firmware, filename_decoded);
g_free (filename_decoded);
- g_free (filename_path);
+
/* next file */
filename = g_dir_read_name (dir);
}
g_dir_close (dir);
/* debugging */
+ array = firmware->priv->array_requested;
for (i=0; i<array->len; i++) {
- filename = g_ptr_array_index (array, i);
- egg_debug ("requested: %s", filename);
+ req = g_ptr_array_index (array, i);
+ egg_debug ("requested: %s", req->filename);
}
/* remove banned files */
gpk_firmware_remove_banned (firmware, array);
/* debugging */
+ array = firmware->priv->array_requested;
for (i=0; i<array->len; i++) {
- filename = g_ptr_array_index (array, i);
- egg_debug ("searching for: %s", filename);
+ req = g_ptr_array_index (array, i);
+ egg_debug ("searching for: %s", req->filename);
}
/* don't spam the user at startup, so wait a little delay */
@@ -525,7 +782,7 @@ gpk_firmware_finalize (GObject *object)
firmware = GPK_FIRMWARE (object);
g_return_if_fail (firmware->priv != NULL);
- g_ptr_array_foreach (firmware->priv->array_requested, (GFunc) g_free, NULL);
+ g_ptr_array_foreach (firmware->priv->array_requested, (GFunc) gpk_firmware_request_free, NULL);
g_ptr_array_free (firmware->priv->array_requested, TRUE);
g_object_unref (firmware->priv->packages_found);
g_object_unref (firmware->priv->client_primary);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]