• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2013 Red Hat, Inc.
4  */
5 
6 #include "config.h"
7 #include <linux/input.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <fcntl.h>
12 #include <libevdev/libevdev-uinput.h>
13 
14 #include "test-common.h"
15 #define UINPUT_NODE "/dev/uinput"
16 
START_TEST(test_uinput_create_device)17 START_TEST(test_uinput_create_device)
18 {
19 	struct libevdev *dev, *dev2;
20 	struct libevdev_uinput *uidev;
21 	int fd, uinput_fd;
22 	unsigned int type, code;
23 	int rc;
24 	const char *devnode;
25 
26 	dev = libevdev_new();
27 	ck_assert(dev != NULL);
28 	libevdev_set_name(dev, TEST_DEVICE_NAME);
29 	libevdev_enable_event_type(dev, EV_SYN);
30 	libevdev_enable_event_type(dev, EV_REL);
31 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
32 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
33 	libevdev_enable_event_code(dev, EV_REL, REL_MAX, NULL);
34 
35 	rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
36 	ck_assert_int_eq(rc, 0);
37 	ck_assert(uidev != NULL);
38 
39 	uinput_fd = libevdev_uinput_get_fd(uidev);
40 	ck_assert_int_gt(uinput_fd, -1);
41 
42 	devnode = libevdev_uinput_get_devnode(uidev);
43 	ck_assert(devnode != NULL);
44 
45 	fd = open(devnode, O_RDONLY);
46 	ck_assert_int_gt(fd, -1);
47 	rc = libevdev_new_from_fd(fd, &dev2);
48 	ck_assert_int_eq(rc, 0);
49 
50 	for (type = 0; type < EV_CNT; type++) {
51 		int max = libevdev_event_type_get_max(type);
52 		if (max == -1)
53 			continue;
54 
55 		for (code = 0; code < (unsigned int)max; code++) {
56 			ck_assert_int_eq(libevdev_has_event_code(dev, type, code),
57 					 libevdev_has_event_code(dev2, type, code));
58 		}
59 	}
60 
61 	libevdev_free(dev);
62 	libevdev_free(dev2);
63 	libevdev_uinput_destroy(uidev);
64 	close(fd);
65 
66 	/* uinput fd is managed, so make sure it did get closed */
67 	ck_assert_int_eq(close(uinput_fd), -1);
68 	ck_assert_int_eq(errno, EBADF);
69 
70 }
71 END_TEST
72 
START_TEST(test_uinput_create_device_invalid)73 START_TEST(test_uinput_create_device_invalid)
74 {
75 	struct libevdev *dev;
76 	struct libevdev_uinput *uidev = NULL;
77 	int rc;
78 
79 	dev = libevdev_new();
80 	ck_assert(dev != NULL);
81 	libevdev_set_name(dev, TEST_DEVICE_NAME);
82 	libevdev_enable_event_type(dev, EV_SYN);
83 	libevdev_enable_event_type(dev, EV_REL);
84 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
85 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
86 
87 	libevdev_set_log_function(test_logfunc_ignore_error, NULL);
88 	rc = libevdev_uinput_create_from_device(dev, -1, &uidev);
89 	ck_assert_int_eq(rc, -EBADF);
90 	ck_assert(uidev == NULL);
91 	libevdev_set_log_function(test_logfunc_abort_on_error, NULL);
92 
93 	libevdev_free(dev);
94 }
95 END_TEST
96 
START_TEST(test_uinput_create_device_from_fd)97 START_TEST(test_uinput_create_device_from_fd)
98 {
99 	struct libevdev *dev, *dev2;
100 	struct libevdev_uinput *uidev;
101 	int fd, fd2;
102 	unsigned int type, code;
103 	int rc;
104 	const char *devnode;
105 
106 	dev = libevdev_new();
107 	ck_assert(dev != NULL);
108 	libevdev_set_name(dev, TEST_DEVICE_NAME);
109 	libevdev_enable_event_type(dev, EV_SYN);
110 	libevdev_enable_event_type(dev, EV_REL);
111 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
112 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
113 
114 	fd = open(UINPUT_NODE, O_RDWR);
115 	ck_assert_int_gt(fd, -1);
116 
117 	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
118 	ck_assert_int_eq(rc, 0);
119 	ck_assert(uidev != NULL);
120 
121 	ck_assert_int_eq(libevdev_uinput_get_fd(uidev), fd);
122 
123 	devnode = libevdev_uinput_get_devnode(uidev);
124 	ck_assert(devnode != NULL);
125 
126 	fd2 = open(devnode, O_RDONLY);
127 	ck_assert_int_gt(fd2, -1);
128 	rc = libevdev_new_from_fd(fd2, &dev2);
129 	ck_assert_int_eq(rc, 0);
130 
131 	for (type = 0; type < EV_CNT; type++) {
132 		int max = libevdev_event_type_get_max(type);
133 		if (max == -1)
134 			continue;
135 
136 		for (code = 0; code < (unsigned int)max; code++) {
137 			ck_assert_int_eq(libevdev_has_event_code(dev, type, code),
138 					 libevdev_has_event_code(dev2, type, code));
139 		}
140 	}
141 
142 	libevdev_free(dev);
143 	libevdev_free(dev2);
144 	libevdev_uinput_destroy(uidev);
145 	close(fd);
146 	close(fd2);
147 }
148 END_TEST
149 
150 #ifdef __FreeBSD__
START_TEST(test_uinput_check_devnode_bsd)151 START_TEST(test_uinput_check_devnode_bsd)
152 {
153 	struct libevdev *dev;
154 	struct libevdev_uinput *uidev, *uidev2;
155 	const char *devnode, *devnode2;
156 	int fd, fd2;
157 	int rc;
158 
159 	dev = libevdev_new();
160 	ck_assert(dev != NULL);
161 	libevdev_set_name(dev, TEST_DEVICE_NAME);
162 	libevdev_enable_event_type(dev, EV_SYN);
163 	libevdev_enable_event_type(dev, EV_REL);
164 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
165 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
166 
167 	fd = open(UINPUT_NODE, O_RDWR);
168 	ck_assert_int_gt(fd, -1);
169 	fd2 = open(UINPUT_NODE, O_RDWR);
170 	ck_assert_int_gt(fd2, -1);
171 
172 	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
173 	ck_assert_int_eq(rc, 0);
174 
175 	/* create a second one */
176 	libevdev_set_name(dev, TEST_DEVICE_NAME " 2");
177 	rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2);
178 	ck_assert_int_eq(rc, 0);
179 
180 	devnode = libevdev_uinput_get_devnode(uidev);
181 	ck_assert(devnode != NULL);
182 
183 	/* get syspath twice returns same pointer */
184 	devnode2 = libevdev_uinput_get_devnode(uidev);
185 	ck_assert(devnode == devnode2);
186 
187 	/* second dev has different devnode */
188 	devnode2 = libevdev_uinput_get_devnode(uidev2);
189 	ck_assert(strcmp(devnode, devnode2) != 0);
190 
191 	libevdev_uinput_destroy(uidev2);
192 	libevdev_uinput_destroy(uidev);
193 
194 	close(fd2);
195 	close(fd);
196 
197 	libevdev_free(dev);
198 }
199 END_TEST
200 
START_TEST(test_uinput_check_syspath_bsd)201 START_TEST(test_uinput_check_syspath_bsd)
202 {
203 	struct libevdev *dev;
204 	struct libevdev_uinput *uidev;
205 	const char *syspath;
206 	int fd;
207 	int rc;
208 
209 	dev = libevdev_new();
210 	ck_assert(dev != NULL);
211 	libevdev_set_name(dev, TEST_DEVICE_NAME);
212 	libevdev_enable_event_type(dev, EV_SYN);
213 	libevdev_enable_event_type(dev, EV_REL);
214 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
215 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
216 
217 	fd = open(UINPUT_NODE, O_RDWR);
218 	ck_assert_int_gt(fd, -1);
219 
220 	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
221 	ck_assert_int_eq(rc, 0);
222 
223 	syspath = libevdev_uinput_get_syspath(uidev);
224 	/* FreeBSD should always return NULL for libevdev_unput_get_syspath() */
225 	ck_assert(syspath == NULL);
226 
227 	libevdev_uinput_destroy(uidev);
228 
229 	close(fd);
230 
231 	libevdev_free(dev);
232 }
233 END_TEST
234 
235 #else /* !__FreeBSD__ */
236 
237 START_TEST(test_uinput_check_syspath_time)
238 {
239 	struct libevdev *dev;
240 	struct libevdev_uinput *uidev, *uidev2;
241 	const char *syspath, *syspath2;
242 	int fd, fd2;
243 	int rc;
244 
245 	dev = libevdev_new();
246 	ck_assert(dev != NULL);
247 	libevdev_set_name(dev, TEST_DEVICE_NAME);
248 	libevdev_enable_event_type(dev, EV_SYN);
249 	libevdev_enable_event_type(dev, EV_REL);
250 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
251 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
252 
253 	fd = open(UINPUT_NODE, O_RDWR);
254 	ck_assert_int_gt(fd, -1);
255 	fd2 = open(UINPUT_NODE, O_RDWR);
256 	ck_assert_int_gt(fd2, -1);
257 
258 	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
259 	ck_assert_int_eq(rc, 0);
260 
261 	/* sleep for 1.5 seconds. sysfs resolution is 1 second, so
262 	   creating both devices without delay means
263 	   libevdev_uinput_get_syspath can't actually differ between
264 	   them. By waiting, we get different ctime for uidev and uidev2,
265 	   and exercise that part of the code.
266 	 */
267 	usleep(1500000);
268 
269 	/* create a second one to test the syspath time filtering code */
270 	rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2);
271 	ck_assert_int_eq(rc, 0);
272 
273 	syspath = libevdev_uinput_get_syspath(uidev);
274 	ck_assert(syspath != NULL);
275 
276 	/* get syspath twice returns same pointer */
277 	syspath2 = libevdev_uinput_get_syspath(uidev);
278 	ck_assert(syspath == syspath2);
279 
280 	/* second dev has different syspath */
281 	syspath2 = libevdev_uinput_get_syspath(uidev2);
282 	ck_assert(strcmp(syspath, syspath2) != 0);
283 
284 	libevdev_free(dev);
285 	libevdev_uinput_destroy(uidev);
286 	libevdev_uinput_destroy(uidev2);
287 
288 	close(fd);
289 	close(fd2);
290 }
291 END_TEST
292 
293 START_TEST(test_uinput_check_syspath_name)
294 {
295 	struct libevdev *dev;
296 	struct libevdev_uinput *uidev, *uidev2;
297 	const char *syspath, *syspath2;
298 	int fd, fd2;
299 	int rc;
300 
301 	dev = libevdev_new();
302 	ck_assert(dev != NULL);
303 	libevdev_set_name(dev, TEST_DEVICE_NAME);
304 	libevdev_enable_event_type(dev, EV_SYN);
305 	libevdev_enable_event_type(dev, EV_REL);
306 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
307 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
308 
309 	fd = open(UINPUT_NODE, O_RDWR);
310 	ck_assert_int_gt(fd, -1);
311 	fd2 = open(UINPUT_NODE, O_RDWR);
312 	ck_assert_int_gt(fd2, -1);
313 
314 	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
315 	ck_assert_int_eq(rc, 0);
316 
317 	/* create a second one to stress the syspath filtering code */
318 	libevdev_set_name(dev, TEST_DEVICE_NAME " 2");
319 	rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2);
320 	ck_assert_int_eq(rc, 0);
321 
322 	syspath = libevdev_uinput_get_syspath(uidev);
323 	ck_assert(syspath != NULL);
324 
325 	/* get syspath twice returns same pointer */
326 	syspath2 = libevdev_uinput_get_syspath(uidev);
327 	ck_assert(syspath == syspath2);
328 
329 	/* second dev has different syspath */
330 	syspath2 = libevdev_uinput_get_syspath(uidev2);
331 	ck_assert(strcmp(syspath, syspath2) != 0);
332 
333 	libevdev_free(dev);
334 	libevdev_uinput_destroy(uidev);
335 	libevdev_uinput_destroy(uidev2);
336 
337 	close(fd);
338 	close(fd2);
339 }
340 END_TEST
341 
342 #endif /* __FreeBSD __ */
343 
START_TEST(test_uinput_events)344 START_TEST(test_uinput_events)
345 {
346 	struct libevdev *dev;
347 	struct libevdev_uinput *uidev;
348 	int fd, fd2;
349 	int rc;
350 	const char *devnode;
351 	int i;
352 	const int nevents = 5;
353 	struct input_event events[] = { {{0, 0}, EV_REL, REL_X, 1},
354 					{{0, 0}, EV_REL, REL_Y, -1},
355 					{{0, 0}, EV_SYN, SYN_REPORT, 0},
356 					{{0, 0}, EV_KEY, BTN_LEFT, 1},
357 					{{0, 0}, EV_SYN, SYN_REPORT, 0}};
358 	struct input_event events_read[nevents];
359 
360 	dev = libevdev_new();
361 	ck_assert(dev != NULL);
362 	libevdev_set_name(dev, TEST_DEVICE_NAME);
363 	libevdev_enable_event_type(dev, EV_SYN);
364 	libevdev_enable_event_type(dev, EV_REL);
365 	libevdev_enable_event_type(dev, EV_KEY);
366 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
367 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
368 	libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL);
369 
370 	fd = open(UINPUT_NODE, O_RDWR);
371 	ck_assert_int_gt(fd, -1);
372 
373 	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
374 	ck_assert_int_eq(rc, 0);
375 	ck_assert(uidev != NULL);
376 
377 	devnode = libevdev_uinput_get_devnode(uidev);
378 	ck_assert(devnode != NULL);
379 
380 	fd2 = open(devnode, O_RDONLY);
381 
382 	for (i = 0; i < nevents; i++)
383 		libevdev_uinput_write_event(uidev, events[i].type, events[i].code, events[i].value);
384 
385 	rc = read(fd2, events_read, sizeof(events_read));
386 	ck_assert_int_eq(rc, sizeof(events_read));
387 
388 	for (i = 0; i < nevents; i++) {
389 		ck_assert_int_eq(events[i].type, events_read[i].type);
390 		ck_assert_int_eq(events[i].code, events_read[i].code);
391 		ck_assert_int_eq(events[i].value, events_read[i].value);
392 	}
393 
394 	libevdev_free(dev);
395 	libevdev_uinput_destroy(uidev);
396 	close(fd);
397 	close(fd2);
398 }
399 END_TEST
400 
START_TEST(test_uinput_properties)401 START_TEST(test_uinput_properties)
402 {
403 	struct libevdev *dev, *dev2;
404 	struct libevdev_uinput *uidev;
405 	int fd;
406 	int rc;
407 	const char *devnode;
408 
409 	dev = libevdev_new();
410 	ck_assert(dev != NULL);
411 	libevdev_set_name(dev, TEST_DEVICE_NAME);
412 	libevdev_enable_event_type(dev, EV_SYN);
413 	libevdev_enable_event_type(dev, EV_REL);
414 	libevdev_enable_event_type(dev, EV_KEY);
415 	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
416 	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
417 	libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL);
418 	libevdev_enable_property(dev, INPUT_PROP_BUTTONPAD);
419 	libevdev_enable_property(dev, INPUT_PROP_MAX);
420 
421 	rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
422 	ck_assert_int_eq(rc, 0);
423 	ck_assert(uidev != NULL);
424 
425 	devnode = libevdev_uinput_get_devnode(uidev);
426 	ck_assert(devnode != NULL);
427 
428 	fd = open(devnode, O_RDONLY);
429 	ck_assert_int_gt(fd, -1);
430 	rc = libevdev_new_from_fd(fd, &dev2);
431 	ck_assert_int_eq(rc, 0);
432 
433 	ck_assert(libevdev_has_property(dev2, INPUT_PROP_BUTTONPAD));
434 	ck_assert(libevdev_has_property(dev2, INPUT_PROP_MAX));
435 
436 	libevdev_free(dev);
437 	libevdev_free(dev2);
438 	libevdev_uinput_destroy(uidev);
439 	close(fd);
440 }
441 END_TEST
442 
TEST_SUITE_ROOT_PRIVILEGES(uinput_suite)443 TEST_SUITE_ROOT_PRIVILEGES(uinput_suite)
444 {
445 	Suite *s = suite_create("libevdev uinput device tests");
446 
447 	add_test(s, test_uinput_create_device);
448 	add_test(s, test_uinput_create_device_invalid);
449 	add_test(s, test_uinput_create_device_from_fd);
450 #ifdef __FreeBSD__
451 	add_test(s, test_uinput_check_devnode_bsd);
452 	add_test(s, test_uinput_check_syspath_bsd);
453 #else
454 	add_test(s, test_uinput_check_syspath_time);
455 	add_test(s, test_uinput_check_syspath_name);
456 #endif
457 
458 	add_test(s, test_uinput_events);
459 
460 	add_test(s, test_uinput_properties);
461 
462 	return s;
463 }
464