1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2014 Red Hat, Inc.
4 */
5
6 #include "config.h"
7 #include <errno.h>
8 #include <inttypes.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <linux/input.h>
16
17 #include <libevdev/libevdev.h>
18 #include <libevdev/libevdev-uinput.h>
19 #include "test-common.h"
20
START_TEST(test_revoke)21 START_TEST(test_revoke)
22 {
23 struct uinput_device* uidev;
24 struct libevdev *dev, *dev2;
25 int rc, fd;
26 struct input_event ev1, ev2;
27 int dev_fd;
28
29 test_create_device(&uidev, &dev,
30 EV_SYN, SYN_REPORT,
31 EV_REL, REL_X,
32 EV_REL, REL_Y,
33 EV_REL, REL_WHEEL,
34 EV_KEY, BTN_LEFT,
35 EV_KEY, BTN_MIDDLE,
36 EV_KEY, BTN_RIGHT,
37 -1);
38
39 fd = open(uinput_device_get_devnode(uidev), O_RDONLY|O_NONBLOCK);
40 ck_assert_int_gt(fd, -1);
41 rc = libevdev_new_from_fd(fd, &dev2);
42 ck_assert_msg(rc == 0, "Failed to create second device: %s", strerror(-rc));
43
44 uinput_device_event(uidev, EV_REL, REL_X, 1);
45 uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
46
47 for (int i = 0; i < 2; i++) {
48 rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
49 ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
50
51 rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
52 ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
53
54 ck_assert_int_eq(ev1.type, ev2.type);
55 ck_assert_int_eq(ev1.code, ev2.code);
56 ck_assert_int_eq(ev1.value, ev2.value);
57 }
58
59 /* revoke first device, expect it closed, second device still open */
60 dev_fd = libevdev_get_fd(dev);
61 ck_assert_int_ge(dev_fd, 0);
62 rc = ioctl(dev_fd, EVIOCREVOKE, NULL);
63 if (rc == -1 && errno == EINVAL) {
64 fprintf(stderr, "WARNING: skipping EVIOCREVOKE test, not suported by current kernel\n");
65 goto out;
66 }
67 ck_assert_msg(rc == 0, "Failed to revoke device: %s", strerror(errno));
68
69 uinput_device_event(uidev, EV_REL, REL_X, 1);
70 uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0);
71
72 rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev1);
73 ck_assert_int_eq(rc, -ENODEV);
74
75 rc = libevdev_next_event(dev2, LIBEVDEV_READ_FLAG_NORMAL, &ev2);
76 ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS);
77
78 out:
79 uinput_device_free(uidev);
80 libevdev_free(dev);
81 libevdev_free(dev2);
82 close(fd);
83 }
84 END_TEST
85
START_TEST(test_revoke_invalid)86 START_TEST(test_revoke_invalid)
87 {
88 struct uinput_device* uidev;
89 struct libevdev *dev;
90 int rc;
91 int dev_fd;
92
93 test_create_device(&uidev, &dev,
94 EV_SYN, SYN_REPORT,
95 EV_REL, REL_X,
96 EV_REL, REL_Y,
97 EV_REL, REL_WHEEL,
98 EV_KEY, BTN_LEFT,
99 EV_KEY, BTN_MIDDLE,
100 EV_KEY, BTN_RIGHT,
101 -1);
102
103 dev_fd = libevdev_get_fd(dev);
104 ck_assert_int_ge(dev_fd, 0);
105 /* ioctl requires 0 as value */
106 rc = ioctl(dev_fd, EVIOCREVOKE, 1);
107 ck_assert_int_eq(rc, -1);
108 ck_assert_int_eq(errno, EINVAL);
109
110 uinput_device_free(uidev);
111 libevdev_free(dev);
112 }
113 END_TEST
114
START_TEST(test_revoke_fail_after)115 START_TEST(test_revoke_fail_after)
116 {
117 struct uinput_device* uidev;
118 struct libevdev *dev, *dev2 = NULL;
119 int rc, fd;
120
121 test_create_device(&uidev, &dev,
122 EV_SYN, SYN_REPORT,
123 EV_REL, REL_X,
124 EV_REL, REL_Y,
125 EV_REL, REL_WHEEL,
126 EV_KEY, BTN_LEFT,
127 EV_KEY, BTN_MIDDLE,
128 EV_KEY, BTN_RIGHT,
129 -1);
130
131 fd = open(uinput_device_get_devnode(uidev), O_RDONLY|O_NONBLOCK);
132 ck_assert_int_gt(fd, -1);
133
134 rc = ioctl(fd, EVIOCREVOKE, NULL);
135 if (rc == -1 && errno == EINVAL) {
136 fprintf(stderr, "WARNING: skipping EVIOCREVOKE test, not suported by current kernel\n");
137 goto out;
138 }
139 ck_assert_msg(rc == 0, "Failed to revoke device: %s", strerror(errno));
140
141 rc = libevdev_new_from_fd(fd, &dev2);
142 ck_assert_int_eq(rc, -ENODEV);
143
144 out:
145 uinput_device_free(uidev);
146 libevdev_free(dev);
147 close(fd);
148 }
149 END_TEST
150
TEST_SUITE_ROOT_PRIVILEGES(kernel)151 TEST_SUITE_ROOT_PRIVILEGES(kernel)
152 {
153 Suite *s = suite_create("kernel");
154
155 add_test(s, test_revoke);
156 add_test(s, test_revoke_invalid);
157 add_test(s, test_revoke_fail_after);
158
159 return s;
160 }
161