[gnome-battery-bench] Catch errors opening /dev/uinput and pass them back to the client
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-battery-bench] Catch errors opening /dev/uinput and pass them back to the client
- Date: Tue, 20 Jan 2015 22:47:18 +0000 (UTC)
commit c9f969f7a50adcc3ae9e52ada0dce7e43185f225
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Tue Jan 20 14:51:31 2015 -0500
Catch errors opening /dev/uinput and pass them back to the client
If we can't open /dev/uinput, store a reason in a GError, and pass
that back over D-Bus to the client.
This prevents mysterious problems where, if /dev/uinput doesn't exist,
the helper simply exits on CreatePlayer.
src/commandline.c | 6 +++-
src/evdev-player.c | 84 +++++++++++++++++++++++++++++++++++++++-----------
src/evdev-player.h | 3 +-
src/remote-player.c | 2 +
src/replay-helper.c | 15 +++++++--
5 files changed, 86 insertions(+), 24 deletions(-)
---
diff --git a/src/commandline.c b/src/commandline.c
index c5fddd6..7002a30 100644
--- a/src/commandline.c
+++ b/src/commandline.c
@@ -160,7 +160,11 @@ play(int argc, char **argv)
static int
play_local(int argc, char **argv)
{
- GbbEventPlayer *player = GBB_EVENT_PLAYER(gbb_evdev_player_new("Gnome Battery Bench Test"));
+ GError *error = NULL;
+ GbbEventPlayer *player = GBB_EVENT_PLAYER(gbb_evdev_player_new("Gnome Battery Bench Test", &error));
+ if (player == NULL)
+ die(error->message);
+
return do_play(player, argc, argv);
}
diff --git a/src/evdev-player.c b/src/evdev-player.c
index 4637631..bb8eb83 100644
--- a/src/evdev-player.c
+++ b/src/evdev-player.c
@@ -24,7 +24,9 @@ struct _GbbEvdevPlayer {
char *filename;
gint64 start_time;
+ int uinput_fd_keyboard;
struct libevdev_uinput *uidev_keyboard;
+ int uinput_fd_mouse;
struct libevdev_uinput *uidev_mouse;
GDataInputStream *input;
@@ -131,8 +133,14 @@ gbb_evdev_player_finalize(GObject *object)
{
GbbEvdevPlayer *player = GBB_EVDEV_PLAYER(object);
- libevdev_uinput_destroy(player->uidev_keyboard);
- libevdev_uinput_destroy(player->uidev_mouse);
+ if (player->uinput_fd_keyboard >= 0)
+ close(player->uinput_fd_keyboard);
+ if (player->uidev_keyboard)
+ libevdev_uinput_destroy(player->uidev_keyboard);
+ if (player->uinput_fd_mouse >= 0)
+ close(player->uinput_fd_keyboard);
+ if (player->uidev_mouse)
+ libevdev_uinput_destroy(player->uidev_mouse);
g_clear_object(&player->input);
@@ -184,6 +192,8 @@ gbb_evdev_player_stop(GbbEventPlayer *event_player)
static void
gbb_evdev_player_init(GbbEvdevPlayer *player)
{
+ player->uinput_fd_keyboard = -1;
+ player->uinput_fd_mouse = -1;
}
static void
@@ -197,11 +207,50 @@ gbb_evdev_player_class_init(GbbEvdevPlayerClass *player_class)
event_player_class->stop = gbb_evdev_player_stop;
}
+static struct libevdev_uinput *
+create_uinput(struct libevdev *dev,
+ int *fd_return,
+ GError **error)
+{
+ /* Since we don't need to access the FD directly, we could use
+ * LIBEVDEV_UINPUT_OPEN_MANAGED instead of opening /dev/input directly.
+ * However, a bug in libevdev 1.2.2 and earlier means that we don't get the
+ * right return code if we use that option - -EBADF is always returned.
+ * We open directly so that the error message will be useful.
+ */
+ int fd = open("/dev/uinput", O_CLOEXEC | O_RDWR);
+ if (fd < 0) {
+ if (errno == EACCES)
+ g_set_error(error, G_IO_ERROR, g_io_error_from_errno(errno),
+ "Need to be root to simulate events");
+ else if (errno == ENOENT)
+ g_set_error(error, G_IO_ERROR, g_io_error_from_errno(errno),
+ "Can't open /dev/uinput: %s. The kernel may not be compiled with uinput support.",
strerror(errno));
+ else
+ g_set_error(error, G_IO_ERROR, g_io_error_from_errno(errno),
+ "Can't open /dev/uinput: %s", strerror(errno));
+
+ return NULL;
+ }
+
+ static struct libevdev_uinput *uinput;
+ int rc = libevdev_uinput_create_from_device(dev, fd, &uinput);
+ if (rc != 0) {
+ g_set_error(error, G_IO_ERROR, g_io_error_from_errno(-rc),
+ "Can't create uinput device: %s", strerror(-rc));
+ close(fd);
+ return NULL;
+ }
+
+ *fd_return = fd;
+ return uinput;
+}
+
GbbEvdevPlayer *
-gbb_evdev_player_new(const char *name)
+gbb_evdev_player_new(const char *name,
+ GError **error)
{
GbbEvdevPlayer *player;
- int rc;
struct libevdev *dev;
int i;
@@ -222,17 +271,11 @@ gbb_evdev_player_new(const char *name)
for (i = 1; i <= 255 - 8; i++)
libevdev_enable_event_code(dev, EV_KEY, i, NULL);
libevdev_enable_event_type(dev, EV_KEY);
- open("/about to create", O_RDONLY);
- rc = libevdev_uinput_create_from_device(dev,
- LIBEVDEV_UINPUT_OPEN_MANAGED,
- &player->uidev_keyboard);
- if (rc != 0) {
- if (rc == -EBADF)
- die("Need to be root to simulate events");
- else
- die("Can't create uinput: %s\n", strerror(-rc));
- }
+
+ player->uidev_keyboard = create_uinput(dev, &player->uinput_fd_keyboard, error);
libevdev_free(dev);
+ if (!player->uidev_keyboard)
+ goto error;
dev = libevdev_new();
char *mouse_name = g_strconcat(name, " - simulated mouse", NULL);
@@ -250,16 +293,19 @@ gbb_evdev_player_new(const char *name)
libevdev_enable_event_type(dev, EV_REL);
libevdev_enable_event_code(dev, EV_REL, REL_WHEEL, NULL);
- rc = libevdev_uinput_create_from_device(dev,
- LIBEVDEV_UINPUT_OPEN_MANAGED,
- &player->uidev_mouse);
- if (rc != 0)
- die("Can't create uinput: %s\n", strerror(-rc));
+ player->uidev_mouse = create_uinput(dev, &player->uinput_fd_mouse, error);
libevdev_free(dev);
+ if (!player->uidev_mouse)
+ goto error;
gbb_event_player_set_ready (GBB_EVENT_PLAYER(player),
libevdev_uinput_get_devnode(player->uidev_keyboard),
libevdev_uinput_get_devnode(player->uidev_mouse));
return player;
+
+error:
+ g_object_unref(player);
+
+ return NULL;
}
diff --git a/src/evdev-player.h b/src/evdev-player.h
index 663a986..6faca3d 100644
--- a/src/evdev-player.h
+++ b/src/evdev-player.h
@@ -12,7 +12,8 @@ typedef struct _GbbEvdevPlayer GbbEvdevPlayer;
#define GBB_IS_EVDEV_PLAYER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GBB_TYPE_EVDEV_PLAYER))
#define GBB_EVDEV_PLAYER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GBB_TYPE_EVDEV_PLAYER,
GbbEvdevPlayerClass))
-GbbEvdevPlayer *gbb_evdev_player_new(const char *name);
+GbbEvdevPlayer *gbb_evdev_player_new(const char *name,
+ GError **error);
GType gbb_evdev_player_get_type(void);
diff --git a/src/remote-player.c b/src/remote-player.c
index 0fdb044..11dac23 100644
--- a/src/remote-player.c
+++ b/src/remote-player.c
@@ -75,6 +75,7 @@ on_play_reply(GObject *source_object,
return;
}
+ g_dbus_error_strip_remote_error(error);
g_warning("Failed to play:s %s", error->message);
g_clear_error(&error);
} else {
@@ -214,6 +215,7 @@ on_create_player_reply(GObject *source_object,
return;
}
+ g_dbus_error_strip_remote_error(error);
die("Error calling CreatePlayer: %s", error->message);
}
diff --git a/src/replay-helper.c b/src/replay-helper.c
index 5330bf9..a6d8705 100644
--- a/src/replay-helper.c
+++ b/src/replay-helper.c
@@ -39,11 +39,14 @@ player_destroy(Player *player)
g_signal_handler_disconnect(player->player, player->finished_connection);
}
- g_object_unref(player->player);
+ g_clear_object(&player->player);
g_dbus_connection_signal_unsubscribe(player->connection,
player->creator_changed_connection);
- g_dbus_connection_unregister_object(player->connection, player->registration_id);
+
+ if (player->registration_id)
+ g_dbus_connection_unregister_object(player->connection, player->registration_id);
+
g_object_unref(player->connection);
g_free(player->name);
g_free(player->path);
@@ -234,7 +237,13 @@ on_checked_authorization(GObject *source_object,
on_name_owner_changed,
player, NULL);
- player->player = GBB_EVENT_PLAYER(gbb_evdev_player_new(player->name));
+ GbbEvdevPlayer *evdev_player = gbb_evdev_player_new(player->name, &error);
+ if (evdev_player == NULL) {
+ g_dbus_method_invocation_take_error(invocation, error);
+ player_destroy(player);
+ return;
+ }
+ player->player = GBB_EVENT_PLAYER(evdev_player);
player->registration_id = g_dbus_connection_register_object(connection,
player->path,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]