mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-12 11:00:32 +01:00
evdev: don't resume a removed device
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@who-t.net> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
3e93d913be
commit
8be1abf58a
4 changed files with 59 additions and 6 deletions
48
src/evdev.c
48
src/evdev.c
|
|
@ -971,7 +971,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;
|
||||
|
|
@ -1008,6 +1009,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;
|
||||
|
|
@ -1255,6 +1257,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)
|
||||
{
|
||||
|
|
@ -1264,11 +1296,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;
|
||||
|
||||
if (evdev_need_mtdev(device)) {
|
||||
|
|
@ -1294,6 +1334,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);
|
||||
|
|
@ -1315,5 +1360,6 @@ evdev_device_destroy(struct evdev_device *device)
|
|||
free(device->mt.slots);
|
||||
free(device->devnode);
|
||||
free(device->sysname);
|
||||
free(device->syspath);
|
||||
free(device);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue