[PATCH libinput 12/17] evdev: don't resume a removed device
Hans de Goede
hdegoede at redhat.com
Sun Sep 14 03:21:12 PDT 2014
Hi,
On 09/03/2014 04:03 AM, Peter Hutterer wrote:
> 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>
Looks good:
Reviewed-by: Hans de Goede <hdegoede at redhat.com>
Regards,
Hans
> ---
> 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) {
>
More information about the wayland-devel
mailing list