• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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