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 17START_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} 71END_TEST 72 73START_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} 95END_TEST 96 97START_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} 148END_TEST 149 150#ifdef __FreeBSD__ 151START_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} 199END_TEST 200 201START_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} 233END_TEST 234 235#else /* !__FreeBSD__ */ 236 237START_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} 291END_TEST 292 293START_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} 340END_TEST 341 342#endif /* __FreeBSD __ */ 343 344START_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} 399END_TEST 400 401START_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} 441END_TEST 442 443TEST_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