From 2546b70a5e507bd1e00fc7ea0e2ed24cd77349af Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 27 Jun 2017 17:46:28 +0200 Subject: [PATCH] logind: filter out input devices that have none of the keys/switche we care about Let's check what keys are there, before we actually hang on to the opened devices. --- src/login/logind-button.c | 46 ++++++++++++++++++++++++++++++++++++++- src/login/logind-core.c | 6 ++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/login/logind-button.c b/src/login/logind-button.c index c47c415e607..e53dd63c297 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -243,6 +243,42 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u return 0; } +static int button_suitable(Button *b) { + unsigned long types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1]; + + assert(b); + assert(b->fd); + + if (ioctl(b->fd, EVIOCGBIT(EV_SYN, sizeof(types)), types) < 0) + return -errno; + + if (bitset_get(types, EV_KEY)) { + unsigned long keys[CONST_MAX4(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND)/ULONG_BITS+1]; + + if (ioctl(b->fd, EVIOCGBIT(EV_KEY, sizeof(keys)), keys) < 0) + return -errno; + + if (bitset_get(keys, KEY_POWER) || + bitset_get(keys, KEY_POWER2) || + bitset_get(keys, KEY_SLEEP) || + bitset_get(keys, KEY_SUSPEND)) + return true; + } + + if (bitset_get(types, EV_SW)) { + unsigned long switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1]; + + if (ioctl(b->fd, EVIOCGBIT(EV_SW, sizeof(switches)), switches) < 0) + return -errno; + + if (bitset_get(switches, SW_LID) || + bitset_get(switches, SW_DOCK)) + return true; + } + + return false; +} + static int button_set_mask(Button *b) { unsigned long types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1] = {}, @@ -308,7 +344,15 @@ int button_open(Button *b) { b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); if (b->fd < 0) - return log_warning_errno(errno, "Failed to open %s: %m", b->name); + return log_warning_errno(errno, "Failed to open %s: %m", p); + + r = button_suitable(b); + if (r < 0) + return log_warning_errno(r, "Failed to determine whether input device is relevant to us: %m"); + if (r == 0) { + log_debug("Device %s does not expose keys or switches relevant to us, ignoring.", p); + return -EADDRNOTAVAIL; + } if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) { r = log_error_errno(errno, "Failed to get input name: %m"); diff --git a/src/login/logind-core.c b/src/login/logind-core.c index eff5a4a36f3..ebe1d686340 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -269,7 +269,11 @@ int manager_process_button_device(Manager *m, struct udev_device *d) { sn = "seat0"; button_set_seat(b, sn); - button_open(b); + + r = button_open(b); + if (r < 0) /* event device doesn't have any keys or switches relevant to us? (or any other error + * opening the device?) let's close the button again. */ + button_free(b); } return 0;