[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