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