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