[PATCH libinput 12/17] evdev: don't resume a removed device
Peter Hutterer
peter.hutterer at who-t.net
Tue Sep 2 19:03:03 PDT 2014
A device may disappear and a new device may re-appear with the same device
node while the original device is suspended. Prevent a device resume to open
the wrong device.
In a path context, a changing syspath is the only indicator we get of the
device changing.
In a udev context, if the device was removed and libinput_dispatch() was
called, we can short-cut the syspath comparison by setting it to NULL.
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
src/evdev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
src/evdev.h | 4 +++-
src/path.c | 9 ++++++---
src/udev-seat.c | 4 +++-
4 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/src/evdev.c b/src/evdev.c
index c9e9b2d..fad9fd9 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -962,7 +962,8 @@ evdev_configure_device(struct evdev_device *device)
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
const char *devnode,
- const char *sysname)
+ const char *sysname,
+ const char *syspath)
{
struct libinput *libinput = seat->libinput;
struct evdev_device *device;
@@ -999,6 +1000,7 @@ evdev_device_create(struct libinput_seat *seat,
device->mtdev = NULL;
device->devnode = strdup(devnode);
device->sysname = strdup(sysname);
+ device->syspath = strdup(syspath);
device->rel.dx = 0;
device->rel.dy = 0;
device->abs.seat_slot = -1;
@@ -1246,6 +1248,36 @@ evdev_device_suspend(struct evdev_device *device)
return 0;
}
+static int
+evdev_device_compare_syspath(struct evdev_device *device, int fd)
+{
+ struct udev *udev = NULL;
+ struct udev_device *udev_device = NULL;
+ const char *syspath;
+ struct stat st;
+ int rc = 1;
+
+ udev = udev_new();
+ if (!udev)
+ goto out;
+
+ if (fstat(fd, &st) < 0)
+ goto out;
+
+ udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
+ if (!device)
+ goto out;
+
+ syspath = udev_device_get_syspath(udev_device);
+ rc = strcmp(syspath, device->syspath);
+out:
+ if (udev_device)
+ udev_device_unref(udev_device);
+ if (udev)
+ udev_unref(udev);
+ return rc;
+}
+
int
evdev_device_resume(struct evdev_device *device)
{
@@ -1255,11 +1287,19 @@ evdev_device_resume(struct evdev_device *device)
if (device->fd != -1)
return 0;
+ if (device->syspath == NULL)
+ return -ENODEV;
+
fd = open_restricted(libinput, device->devnode, O_RDWR | O_NONBLOCK);
if (fd < 0)
return -errno;
+ if (evdev_device_compare_syspath(device, fd)) {
+ close_restricted(libinput, fd);
+ return -ENODEV;
+ }
+
device->fd = fd;
device->source =
libinput_add_fd(libinput, fd, evdev_device_dispatch, device);
@@ -1276,6 +1316,11 @@ evdev_device_remove(struct evdev_device *device)
{
evdev_device_suspend(device);
+ /* A device may be removed while suspended. Free the syspath to
+ * skip re-opening a different device with the same node */
+ free(device->syspath);
+ device->syspath = NULL;
+
list_remove(&device->base.link);
notify_removed_device(&device->base);
@@ -1297,5 +1342,6 @@ evdev_device_destroy(struct evdev_device *device)
free(device->mt.slots);
free(device->devnode);
free(device->sysname);
+ free(device->syspath);
free(device);
}
diff --git a/src/evdev.h b/src/evdev.h
index 2af6828..bdd4a4e 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -63,6 +63,7 @@ struct evdev_device {
char *output_name;
char *devnode;
char *sysname;
+ char *syspath;
const char *devname;
int fd;
struct {
@@ -134,7 +135,8 @@ struct evdev_dispatch {
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
const char *devnode,
- const char *sysname);
+ const char *sysname,
+ const char *syspath);
struct evdev_dispatch *
evdev_touchpad_create(struct evdev_device *device);
diff --git a/src/path.c b/src/path.c
index e9c0ee8..3752751 100644
--- a/src/path.c
+++ b/src/path.c
@@ -112,6 +112,7 @@ path_seat_get_named(struct path_input *input,
static int
path_get_udev_properties(const char *path,
char **sysname,
+ char **syspath,
char **seat_name,
char **seat_logical_name)
{
@@ -133,6 +134,7 @@ path_get_udev_properties(const char *path,
goto out;
*sysname = strdup(udev_device_get_sysname(device));
+ *syspath = strdup(udev_device_get_syspath(device));
seat = udev_device_get_property_value(device, "ID_SEAT");
*seat_name = strdup(seat ? seat : default_seat);
@@ -155,10 +157,10 @@ path_device_enable(struct path_input *input, const char *devnode)
{
struct path_seat *seat;
struct evdev_device *device = NULL;
- char *sysname = NULL;
+ char *sysname = NULL, *syspath = NULL;
char *seat_name = NULL, *seat_logical_name = NULL;
- if (path_get_udev_properties(devnode, &sysname,
+ if (path_get_udev_properties(devnode, &sysname, &syspath,
&seat_name, &seat_logical_name) == -1) {
log_info(&input->base,
"failed to obtain sysname for device '%s'.\n",
@@ -180,7 +182,7 @@ path_device_enable(struct path_input *input, const char *devnode)
}
}
- device = evdev_device_create(&seat->base, devnode, sysname);
+ device = evdev_device_create(&seat->base, devnode, sysname, syspath);
libinput_seat_unref(&seat->base);
if (device == EVDEV_UNHANDLED_DEVICE) {
@@ -198,6 +200,7 @@ path_device_enable(struct path_input *input, const char *devnode)
out:
free(sysname);
+ free(syspath);
free(seat_name);
free(seat_logical_name);
diff --git a/src/udev-seat.c b/src/udev-seat.c
index ccff35c..f2be66e 100644
--- a/src/udev-seat.c
+++ b/src/udev-seat.c
@@ -47,6 +47,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
struct evdev_device *device;
const char *devnode;
const char *sysname;
+ const char *syspath;
const char *device_seat, *seat_name, *output_name;
const char *calibration_values;
float calibration[6];
@@ -61,6 +62,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
devnode = udev_device_get_devnode(udev_device);
sysname = udev_device_get_sysname(udev_device);
+ syspath = udev_device_get_syspath(udev_device);
/* Search for matching logical seat */
seat_name = udev_device_get_property_value(udev_device, "WL_SEAT");
@@ -77,7 +79,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
return -1;
}
- device = evdev_device_create(&seat->base, devnode, sysname);
+ device = evdev_device_create(&seat->base, devnode, sysname, syspath);
libinput_seat_unref(&seat->base);
if (device == EVDEV_UNHANDLED_DEVICE) {
--
1.9.3
More information about the wayland-devel
mailing list