• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
4  * Copyright (c) Linux Test Project, 2019-2023
5  */
6 
7 /*\
8  * [Description]
9  * Very simple uevent netlink socket test.
10  *
11  * We fork a child that listens for a kernel events while parents creates and
12  * removes a virtual mouse which produces add and remove event for the device
13  * itself and for two event handlers called eventX and mouseY.
14  */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/wait.h>
19 #include <sys/sysmacros.h>
20 #include <linux/uinput.h>
21 #include "tst_test.h"
22 #include "tst_uinput.h"
23 #include "uevent.h"
24 
25 static int mouse_fd;
26 
create_uinput_mouse(void)27 static void create_uinput_mouse(void)
28 {
29 	mouse_fd = open_uinput();
30 	if (mouse_fd == -1)
31 		tst_brk(TCONF, "Virtual device is not available");
32 
33 	setup_mouse_events(mouse_fd);
34 	create_input_device(mouse_fd);
35 }
36 
destroy_uinput_mouse(void)37 static void destroy_uinput_mouse(void)
38 {
39 	destroy_input_device(mouse_fd);
40 }
41 
get_minor_major(char * device,char * minor,char * major,size_t buf_sizes)42 static void get_minor_major(char *device, char *minor, char *major, size_t buf_sizes)
43 {
44 	char path[1024];
45 	struct stat stbuf;
46 
47 	snprintf(path, sizeof(path), "/dev/input/%s", device);
48 
49 	SAFE_STAT(path, &stbuf);
50 
51 	snprintf(major, buf_sizes, "MAJOR=%i", major(stbuf.st_rdev));
52 	snprintf(minor, buf_sizes, "MINOR=%i", minor(stbuf.st_rdev));
53 }
54 
55 #define MINOR_MAJOR_SIZE 32
56 
verify_uevent(void)57 static void verify_uevent(void)
58 {
59 	int pid, fd;
60 	char add_msg[1024];
61 	char rem_msg[1024];
62 	char dev_path[1024];
63 	char add_msg_event1[1024];
64 	char rem_msg_event1[1024];
65 	char dev_path_event1[1024];
66 	char add_msg_event2[1024];
67 	char rem_msg_event2[1024];
68 	char dev_path_event2[1024];
69 	char dev_name1[1024];
70 	char dev_name2[1024];
71 
72 	char minor_event1[MINOR_MAJOR_SIZE];
73 	char minor_event2[MINOR_MAJOR_SIZE];
74 	char major_event1[MINOR_MAJOR_SIZE];
75 	char major_event2[MINOR_MAJOR_SIZE];
76 
77 	char *handlers, *handler1, *handler2, *sysname;
78 	struct uevent_desc add = {
79 		.msg = add_msg,
80 		.value_cnt = 7,
81 		.values = (const char*[]) {
82 			"ACTION=add",
83 			dev_path,
84 			"SUBSYSTEM=input",
85 			"NAME=\"virtual-device-ltp\"",
86 			"PROP=0",
87 			"EV=7",
88 			"REL=3",
89 		}
90 	};
91 
92 	struct uevent_desc add_event1 = {
93 		.msg = add_msg_event1,
94 		.value_cnt = 6,
95 		.values = (const char*[]) {
96 			"ACTION=add",
97 			"SUBSYSTEM=input",
98 			dev_name1,
99 			dev_path_event1,
100 			minor_event1,
101 			major_event1,
102 		}
103 	};
104 
105 	struct uevent_desc add_event2 = {
106 		.msg = add_msg_event2,
107 		.value_cnt = 6,
108 		.values = (const char*[]) {
109 			"ACTION=add",
110 			"SUBSYSTEM=input",
111 			dev_name2,
112 			dev_path_event2,
113 			minor_event2,
114 			major_event2,
115 		}
116 	};
117 
118 	struct uevent_desc rem_event1 = {
119 		.msg = rem_msg_event1,
120 		.value_cnt = 6,
121 		.values = (const char*[]) {
122 			"ACTION=remove",
123 			"SUBSYSTEM=input",
124 			dev_name1,
125 			dev_path_event1,
126 			minor_event1,
127 			major_event1,
128 		}
129 	};
130 
131 	struct uevent_desc rem_event2 = {
132 		.msg = rem_msg_event2,
133 		.value_cnt = 6,
134 		.values = (const char*[]) {
135 			"ACTION=remove",
136 			"SUBSYSTEM=input",
137 			dev_name2,
138 			dev_path_event2,
139 			minor_event2,
140 			major_event2,
141 		}
142 	};
143 
144 	struct uevent_desc rem = {
145 		.msg = rem_msg,
146 		.value_cnt = 7,
147 		.values = (const char*[]) {
148 			"ACTION=remove",
149 			dev_path,
150 			"SUBSYSTEM=input",
151 			"NAME=\"virtual-device-ltp\"",
152 			"PROP=0",
153 			"EV=7",
154 			"REL=3",
155 		}
156 	};
157 
158 	const struct uevent_desc *const uevents[] = {
159 		&add,
160 		&add_event1,
161 		&add_event2,
162 		&rem_event1,
163 		&rem_event2,
164 		&rem,
165 		NULL
166 	};
167 
168 	fd = open_uevent_netlink();
169 
170 	create_uinput_mouse();
171 
172 	sysname = get_input_field_value('S');
173 	handlers = get_input_field_value('H');
174 
175 	if (!sysname)
176 		tst_brk(TBROK, "Expected /devices/virtual/input/inputN sysname!");
177 
178 	tst_res(TINFO, "Sysname: %s", sysname);
179 	tst_res(TINFO, "Handlers: %s", handlers);
180 
181 	handler1 = strtok(handlers, " ");
182 	if (!handler1)
183 		tst_brk(TBROK, "Expected mouseX and eventY handlers!");
184 
185 	get_minor_major(handler1, minor_event1, major_event1, MINOR_MAJOR_SIZE);
186 
187 	handler2 = strtok(NULL, " ");
188 	if (!handler2)
189 		tst_brk(TBROK, "Expected mouseX and eventY handlers!");
190 
191 	get_minor_major(handler2, minor_event2, major_event2, MINOR_MAJOR_SIZE);
192 
193 	destroy_uinput_mouse();
194 
195 	snprintf(add_msg, sizeof(add_msg), "add@%s", sysname);
196 
197 	snprintf(rem_msg, sizeof(rem_msg), "remove@%s", sysname);
198 
199 	snprintf(dev_path, sizeof(dev_path), "DEVPATH=%s", sysname);
200 
201 	snprintf(add_msg_event1, sizeof(add_msg_event1),
202 		"add@%s/%s", sysname, handler1);
203 
204 	snprintf(rem_msg_event1, sizeof(rem_msg_event1),
205 		"remove@%s/%s", sysname, handler1);
206 
207 	snprintf(dev_path_event1, sizeof(dev_path_event1),
208 		"DEVPATH=%s/%s", sysname, handler1);
209 
210 	snprintf(dev_name1, sizeof(dev_name1),
211 		"DEVNAME=input/%s", handler1);
212 
213 
214 	snprintf(add_msg_event2, sizeof(add_msg_event2),
215 		"add@%s/%s", sysname, handler2);
216 
217 	snprintf(rem_msg_event2, sizeof(rem_msg_event2),
218 		"remove@%s/%s", sysname, handler2);
219 
220 	snprintf(dev_path_event2, sizeof(dev_path_event2),
221 		"DEVPATH=%s/%s", sysname, handler2);
222 
223 	snprintf(dev_name2, sizeof(dev_name2),
224 		"DEVNAME=input/%s", handler2);
225 
226 	free(sysname);
227 	free(handlers);
228 
229 	pid = SAFE_FORK();
230 	if (!pid) {
231 		wait_for_uevents(fd, uevents);
232 		exit(0);
233 	}
234 
235 	SAFE_CLOSE(fd);
236 	wait_for_pid(pid);
237 }
238 
239 static struct tst_test test = {
240 	.test_all = verify_uevent,
241 	.forks_child = 1,
242 	.needs_checkpoints = 1,
243 	.needs_drivers = (const char *const[]) {
244 		"uinput",
245 		NULL
246 	},
247 	.needs_root = 1,
248 };
249