1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com>
4 * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
5 */
6
7 #include <linux/input.h>
8 #include <linux/uinput.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #define TST_NO_DEFAULT_MAIN
13 #include "tst_test.h"
14
15 #include "tst_uinput.h"
16 #include "tst_safe_stdio.h"
17
18 #define VIRTUAL_DEVICE "virtual-device-ltp"
19
20 static const char *uinput_paths[] = {
21 "/dev/input/uinput",
22 "/dev/uinput",
23 };
24
open_uinput(void)25 int open_uinput(void)
26 {
27 unsigned int i;
28 int fd;
29
30 for (i = 0; i < ARRAY_SIZE(uinput_paths); i++) {
31 fd = open(uinput_paths[i], O_WRONLY | O_NONBLOCK);
32
33 if (fd > 0) {
34 tst_res(TINFO, "Found uinput dev at %s", uinput_paths[i]);
35 return fd;
36 }
37
38 if (fd < 0 && errno != ENOENT) {
39 tst_brk(TBROK | TERRNO, "open(%s)", uinput_paths[i]);
40 }
41 }
42
43 return -1;
44 }
45
46
47 #define SYSFS_PREFIX "Sysfs="
48 #define HANDLERS_PREFIX "Handlers="
49
parse_field(char * line,char field)50 static char *parse_field(char *line, char field)
51 {
52 char *value;
53
54 switch (field) {
55 case 'H':
56 value = strstr(line, HANDLERS_PREFIX) + sizeof(HANDLERS_PREFIX) - 1;
57 break;
58 case 'S':
59 value = strstr(line, SYSFS_PREFIX) + sizeof(SYSFS_PREFIX) - 1;
60 break;
61 default:
62 return NULL;
63 }
64
65 value[strlen(value) - 1] = 0;
66
67 return strdup(value);
68 }
69
get_input_field_value(char field)70 char *get_input_field_value(char field)
71 {
72 FILE *file;
73 char line[1024];
74 int flag = 0;
75
76 file = fopen("/proc/bus/input/devices", "r");
77 if (!file)
78 return NULL;
79
80 while (fgets(line, sizeof(line), file)) {
81 if (strstr(line, "N: Name=\""VIRTUAL_DEVICE"\""))
82 flag = 1;
83
84 if (flag) {
85 if (line[0] == field)
86 return parse_field(line, field);
87
88 if (line[0] == '\n')
89 flag = 0;
90 }
91 }
92
93 fclose(file);
94 return NULL;
95 }
96
check_device(void)97 static int check_device(void)
98 {
99 FILE *file;
100 char line[256];
101
102 file = fopen("/proc/bus/input/devices", "r");
103 if (!file)
104 return 0;
105
106 while (fgets(line, sizeof(line), file)) {
107 if (strstr(line, "Name=\""VIRTUAL_DEVICE"\""))
108 return 1;
109 }
110
111 fclose(file);
112
113 return 0;
114 }
115
setup_mouse_events(int fd)116 void setup_mouse_events(int fd)
117 {
118 SAFE_IOCTL(fd, UI_SET_EVBIT, EV_KEY);
119 SAFE_IOCTL(fd, UI_SET_KEYBIT, BTN_LEFT);
120 SAFE_IOCTL(fd, UI_SET_EVBIT, EV_REL);
121 SAFE_IOCTL(fd, UI_SET_RELBIT, REL_X);
122 SAFE_IOCTL(fd, UI_SET_RELBIT, REL_Y);
123 }
124
destroy_input_device(int fd)125 void destroy_input_device(int fd)
126 {
127 SAFE_IOCTL(fd, UI_DEV_DESTROY, NULL);
128 SAFE_CLOSE(fd);
129 }
130
check_ui_get_sysname_ioctl(int fd)131 static void check_ui_get_sysname_ioctl(int fd)
132 {
133 char sys_name[256];
134 char dev_name[256];
135 char *path;
136
137 SAFE_IOCTL(fd, UI_GET_SYSNAME(sizeof(sys_name)), sys_name, NULL);
138 SAFE_ASPRINTF(&path, "/sys/devices/virtual/input/%s/name", sys_name);
139
140 if (FILE_SCANF(path, "%s", dev_name)) {
141 free(path);
142 tst_brk(TBROK|TERRNO, "Failed to read '%s'", path);
143 return;
144 }
145
146 if (strcmp(VIRTUAL_DEVICE, dev_name)) {
147 free(path);
148 tst_brk(TBROK, "ioctl UI_GET_SYSNAME returned wrong name");
149 }
150
151 free(path);
152 }
153
create_input_device(int fd)154 void create_input_device(int fd)
155 {
156 int nb;
157 struct uinput_user_dev uidev = {
158 .name = VIRTUAL_DEVICE,
159 .id = {
160 .bustype = BUS_USB,
161 .vendor = 0x1,
162 .product = 0x1,
163 .version = 1,
164 }
165 };
166
167 SAFE_WRITE(SAFE_WRITE_ALL, fd, &uidev, sizeof(uidev));
168 SAFE_IOCTL(fd, UI_DEV_CREATE, NULL);
169
170 for (nb = 100; nb > 0; nb--) {
171 if (check_device()) {
172 check_ui_get_sysname_ioctl(fd);
173 return;
174 }
175 usleep(10000);
176 }
177
178 destroy_input_device(fd);
179 tst_brk(TBROK, "Failed to create device");
180 }
181