[PATCH libevdev 2/2] Add support for EVIOCREVOKE
David Herrmann
dh.herrmann at gmail.com
Wed Jan 8 04:09:27 PST 2014
Hi
On Wed, Jan 8, 2014 at 2:28 AM, Peter Hutterer <peter.hutterer at who-t.net> wrote:
> New in 3.12, EVIOCREVOKE revokes access to an evdev device.
> The process calling revoke is unlikely to be the same process as the one
> handling the device, so provide a convenience call to just wrap the
> ioctl instead of requiring a full libevdev device.
>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
> In two minds about this one: I suspect that the only users of EVIOCREVOKE
> are low-level tools that probably don't use libevdev anyway, so even the
> libevdev_revoke_fd() call won't make them drag in libevdev as dependency.
>
> So I'm mostly sending this to the list for the archivse, we probably
> shouldn't merge this until we have a real need for it.
Hm, I fully agree here, but I also like to see the test-cases in the
libevdev suite. So how about we add the functions but don't export it?
Our GNU-ld --gc-sections flag will remove it from the DSO, anyway, so
we only add compile-time overhead. I like the fact that with libevdev
we have a quite comprehensive test-suite for the kernel evdev
interface and I think we should extend it as much as possible.
> libevdev/libevdev.c | 24 ++++++++++
> libevdev/libevdev.h | 37 ++++++++++++++
> test/test-libevdev-init.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 181 insertions(+)
>
> diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
> index 8a37204..a99332c 100644
> --- a/libevdev/libevdev.c
> +++ b/libevdev/libevdev.c
> @@ -1446,3 +1446,27 @@ libevdev_set_clock_id(struct libevdev *dev, int clockid)
>
> return ioctl(dev->fd, EVIOCSCLOCKID, &clockid) ? -errno : 0;
> }
> +
> +LIBEVDEV_EXPORT int
> +libevdev_revoke(struct libevdev *dev)
> +{
> + if (!dev->initialized) {
> + log_bug("device not initialized. call libevdev_set_fd() first\n");
> + return -EBADF;
> + } else if (dev->fd < 0)
> + return -EBADF;
> +
> + return libevdev_revoke_fd(dev->fd);
> +}
> +
> +LIBEVDEV_EXPORT int
> +libevdev_revoke_fd(int fd)
> +{
> + int rc;
> +
> + if (fd < 0)
> + return -EBADF;
> +
> + rc = ioctl(fd, EVIOCREVOKE, NULL);
> + return rc ? -errno : 0;
> +}
> diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h
> index f5ceda0..08ab8e6 100644
> --- a/libevdev/libevdev.h
> +++ b/libevdev/libevdev.h
> @@ -310,6 +310,8 @@ extern "C" {
> * <dd>supported, see libevdev_grab()</dd>
> * <dt>EVIOCSCLOCKID:</dt>
> * <dd>supported, see libevdev_set_clock_id()</dd>
> + * <dt>EVIOCREVOKE:</dt>
> + * <dd>supported, see libevdev_revoke(), libevdev_revoke_fd()</dd>
> * </dl>
> *
> */
> @@ -1635,6 +1637,41 @@ int libevdev_event_code_from_name_n(unsigned int type, const char *name,
> */
> int libevdev_get_repeat(const struct libevdev *dev, int *delay, int *period);
>
> +/**
> + * @ingroup kernel
> + *
> + * Revoke access to the file descriptor by calling EVIOCREVOKE on it.
> + * Once issued, this file descriptor becomes mute and will not send
> + * any more events. Reading or writing to the fd will fail.
> + *
> + * @param dev The evdev device, already initialized with libevdev_set_fd()
> + * @return 0 on success or a negative errno on failure
> + * @retval -EINVAL The kernel does not support the EVIOCREVOKE ioctl.
> + *
> + * @see libevdev_revoke_fd
> + */
> +int libevdev_revoke(struct libevdev *dev);
> +
> +/**
> + * @ingroup kernel
> + *
> + * Revoke access to the file descriptor by calling EVIOCREVOKE on it.
> + * Once issued, this file descriptor becomes mute and will not send
> + * any more events. Reading or writing to the fd will fail.
> + *
> + * This call is a convenience call for clients that do not want to handle
> + * ioctls manually but do not need or want to open a full libevdev device.
> + *
> + * If you have a libevdev device anyway, use libevdev_revoke() instead.
> + *
> + * @param fd A file descriptor to an evdev device
> + * @return 0 on success or a negative errno on failure
> + * @retval -EINVAL The kernel does not support the EVIOCREVOKE ioctl.
> + *
> + * @see libevdev_revoke
> + */
> +int libevdev_revoke_fd(int fd);
> +
>
> /********* DEPRECATED SECTION *********/
> #if defined(__GNUC__) && __GNUC__ >= 4
> diff --git a/test/test-libevdev-init.c b/test/test-libevdev-init.c
> index bf0b874..eb4916f 100644
> --- a/test/test-libevdev-init.c
> +++ b/test/test-libevdev-init.c
> @@ -28,6 +28,7 @@
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> +#include <stdio.h>
>
> #include <libevdev/libevdev-uinput.h>
> #include "test-common.h"
> @@ -366,6 +367,120 @@ START_TEST(test_clock_id_events)
> END_TEST
>
>
> +START_TEST(test_revoke)
> +{
> + struct uinput_device* uidev;
> + struct libevdev *dev, *dev2;
> + int rc, fd;
> + struct input_event ev1, ev2;
> +
> + rc = test_create_device(&uidev, &dev,
> + EV_SYN, SYN_REPORT,
> + EV_REL, REL_X,
> + EV_REL, REL_Y,
> + EV_REL, REL_WHEEL,
> + EV_KEY, BTN_LEFT,
> + EV_KEY, BTN_MIDDLE,
> + EV_KEY, BTN_RIGHT,
> + -1);
> + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
> +
> + fd = open(uinput_device_get_devnode(uidev), O_RDONLY|O_NONBLOCK);
> + ck_assert_int_gt(fd, -1);
> + rc = libevdev_new_from_fd(fd, &dev2);
> + ck_assert_msg(rc == 0, "Failed to create second device: %s", strerror(-rc));
> +
> + uinput_device_event(uidev, EV_REL, REL_X, 1);
> + uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
> +
> + rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
> + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
> +
> + rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
> + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
> +
> + ck_assert_int_eq(ev1.type, ev2.type);
> + ck_assert_int_eq(ev1.code, ev2.code);
> + ck_assert_int_eq(ev1.value, ev2.value);
> +
> + /* revoke first device, expect it closed, second device still open */
> + rc = libevdev_revoke(dev);
> + if (rc == -EINVAL) {
> + fprintf(stderr, "WARNING: skipping libevdev_revoke test, not suported by current kernel\n");
> + goto out;
autotools-TESTS actually supports skipping tests (I think by returning
72 or something). We currently run all tests as a single test-binary,
so we cannot use that. Maybe some day we can split them up so the
test-results properly resemble the real tests-status.
And I really hate the fact that we get EINVAL instead of ENOSYS.. but
that's how evdev always worked for invalid ioctls, *sigh*.
Thanks
David
> + }
> +
> + rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
> + ck_assert_int_eq(rc, -ENODEV);
> +
> + rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
> + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
> +
> +out:
> + uinput_device_free(uidev);
> + libevdev_free(dev);
> + libevdev_free(dev2);
> + close(fd);
> +}
> +END_TEST
> +
> +START_TEST(test_revoke_fd)
> +{
> + struct uinput_device* uidev;
> + struct libevdev *dev, *dev2;
> + int rc, fd;
> + struct input_event ev1, ev2;
> +
> + rc = test_create_device(&uidev, &dev,
> + EV_SYN, SYN_REPORT,
> + EV_REL, REL_X,
> + EV_REL, REL_Y,
> + EV_REL, REL_WHEEL,
> + EV_KEY, BTN_LEFT,
> + EV_KEY, BTN_MIDDLE,
> + EV_KEY, BTN_RIGHT,
> + -1);
> + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
> +
> + fd = open(uinput_device_get_devnode(uidev), O_RDONLY|O_NONBLOCK);
> + ck_assert_int_gt(fd, -1);
> + rc = libevdev_new_from_fd(fd, &dev2);
> + ck_assert_msg(rc == 0, "Failed to create second device: %s", strerror(-rc));
> +
> + uinput_device_event(uidev, EV_REL, REL_X, 1);
> + uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
> +
> + rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
> + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
> +
> + rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
> + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
> +
> + ck_assert_int_eq(ev1.type, ev2.type);
> + ck_assert_int_eq(ev1.code, ev2.code);
> + ck_assert_int_eq(ev1.value, ev2.value);
> +
> + /* revoke second device based on fd */
> + rc = libevdev_revoke_fd(fd);
> + if (rc == -EINVAL) {
> + fprintf(stderr, "::: WARNING: skipping libevdev_revoke_fd test, not suported by current kernel\n");
> + goto out;
> + }
> +
> + rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
> + ck_assert_int_eq(rc, -ENODEV);
> +
> + rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
> + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
> +
> +out:
> + uinput_device_free(uidev);
> + libevdev_free(dev);
> + libevdev_free(dev2);
> + close(fd);
> +}
> +END_TEST
> +
> Suite *
> libevdev_init_test(void)
> {
> @@ -397,5 +512,10 @@ libevdev_init_test(void)
> tcase_add_test(tc, test_clock_id_events);
> suite_add_tcase(s, tc);
>
> + tc = tcase_create("revoke");
> + tcase_add_test(tc, test_revoke);
> + tcase_add_test(tc, test_revoke_fd);
> + suite_add_tcase(s, tc);
> +
> return s;
> }
> --
> 1.8.4.2
>
> _______________________________________________
> Input-tools mailing list
> Input-tools at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/input-tools
More information about the Input-tools
mailing list