xref: /aosp_15_r20/external/ltp/testcases/kernel/uevents/uevent03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2019 Cyril Hrubis <[email protected]>
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 	setup_mouse_events(mouse_fd);
31 	create_input_device(mouse_fd);
32 }
33 
destroy_uinput_mouse(void)34 static void destroy_uinput_mouse(void)
35 {
36 	destroy_input_device(mouse_fd);
37 }
38 
get_minor_major(char * device,char * minor,char * major,size_t buf_sizes)39 static void get_minor_major(char *device, char *minor, char *major, size_t buf_sizes)
40 {
41 	char path[1024];
42 	struct stat stbuf;
43 
44 	snprintf(path, sizeof(path), "/dev/input/%s", device);
45 
46 	SAFE_STAT(path, &stbuf);
47 
48 	snprintf(major, buf_sizes, "MAJOR=%i", major(stbuf.st_rdev));
49 	snprintf(minor, buf_sizes, "MINOR=%i", minor(stbuf.st_rdev));
50 }
51 
52 #define MINOR_MAJOR_SIZE 32
53 
verify_uevent(void)54 static void verify_uevent(void)
55 {
56 	int pid, fd;
57 	char add_msg[1024];
58 	char rem_msg[1024];
59 	char dev_path[1024];
60 	char add_msg_event1[1024];
61 	char rem_msg_event1[1024];
62 	char dev_path_event1[1024];
63 	char add_msg_event2[1024];
64 	char rem_msg_event2[1024];
65 	char dev_path_event2[1024];
66 	char dev_name1[1024];
67 	char dev_name2[1024];
68 
69 	char minor_event1[MINOR_MAJOR_SIZE];
70 	char minor_event2[MINOR_MAJOR_SIZE];
71 	char major_event1[MINOR_MAJOR_SIZE];
72 	char major_event2[MINOR_MAJOR_SIZE];
73 
74 	char *handlers, *handler1, *handler2, *sysname;
75 	struct uevent_desc add = {
76 		.msg = add_msg,
77 		.value_cnt = 7,
78 		.values = (const char*[]) {
79 			"ACTION=add",
80 			dev_path,
81 			"SUBSYSTEM=input",
82 			"NAME=\"virtual-device-ltp\"",
83 			"PROP=0",
84 			"EV=7",
85 			"REL=3",
86 		}
87 	};
88 
89 	struct uevent_desc add_event1 = {
90 		.msg = add_msg_event1,
91 		.value_cnt = 6,
92 		.values = (const char*[]) {
93 			"ACTION=add",
94 			"SUBSYSTEM=input",
95 			dev_name1,
96 			dev_path_event1,
97 			minor_event1,
98 			major_event1,
99 		}
100 	};
101 
102 	struct uevent_desc add_event2 = {
103 		.msg = add_msg_event2,
104 		.value_cnt = 6,
105 		.values = (const char*[]) {
106 			"ACTION=add",
107 			"SUBSYSTEM=input",
108 			dev_name2,
109 			dev_path_event2,
110 			minor_event2,
111 			major_event2,
112 		}
113 	};
114 
115 	struct uevent_desc rem_event1 = {
116 		.msg = rem_msg_event1,
117 		.value_cnt = 6,
118 		.values = (const char*[]) {
119 			"ACTION=remove",
120 			"SUBSYSTEM=input",
121 			dev_name1,
122 			dev_path_event1,
123 			minor_event1,
124 			major_event1,
125 		}
126 	};
127 
128 	struct uevent_desc rem_event2 = {
129 		.msg = rem_msg_event2,
130 		.value_cnt = 6,
131 		.values = (const char*[]) {
132 			"ACTION=remove",
133 			"SUBSYSTEM=input",
134 			dev_name2,
135 			dev_path_event2,
136 			minor_event2,
137 			major_event2,
138 		}
139 	};
140 
141 	struct uevent_desc rem = {
142 		.msg = rem_msg,
143 		.value_cnt = 7,
144 		.values = (const char*[]) {
145 			"ACTION=remove",
146 			dev_path,
147 			"SUBSYSTEM=input",
148 			"NAME=\"virtual-device-ltp\"",
149 			"PROP=0",
150 			"EV=7",
151 			"REL=3",
152 		}
153 	};
154 
155 	const struct uevent_desc *const uevents[] = {
156 		&add,
157 		&add_event1,
158 		&add_event2,
159 		&rem_event1,
160 		&rem_event2,
161 		&rem,
162 		NULL
163 	};
164 
165 	fd = open_uevent_netlink();
166 
167 	create_uinput_mouse();
168 
169 	sysname = get_input_field_value('S');
170 	handlers = get_input_field_value('H');
171 
172 	if (!sysname)
173 		tst_brk(TBROK, "Expected /devices/virtual/input/inputN sysname!");
174 
175 	tst_res(TINFO, "Sysname: %s", sysname);
176 	tst_res(TINFO, "Handlers: %s", handlers);
177 
178 	handler1 = strtok(handlers, " ");
179 	if (!handler1)
180 		tst_brk(TBROK, "Expected mouseX and eventY handlers!");
181 
182 	get_minor_major(handler1, minor_event1, major_event1, MINOR_MAJOR_SIZE);
183 
184 	handler2 = strtok(NULL, " ");
185 	if (!handler2)
186 		tst_brk(TBROK, "Expected mouseX and eventY handlers!");
187 
188 	get_minor_major(handler2, minor_event2, major_event2, MINOR_MAJOR_SIZE);
189 
190 	destroy_uinput_mouse();
191 
192 	snprintf(add_msg, sizeof(add_msg), "add@%s", sysname);
193 
194 	snprintf(rem_msg, sizeof(rem_msg), "remove@%s", sysname);
195 
196 	snprintf(dev_path, sizeof(dev_path), "DEVPATH=%s", sysname);
197 
198 	snprintf(add_msg_event1, sizeof(add_msg_event1),
199 		"add@%s/%s", sysname, handler1);
200 
201 	snprintf(rem_msg_event1, sizeof(rem_msg_event1),
202 		"remove@%s/%s", sysname, handler1);
203 
204 	snprintf(dev_path_event1, sizeof(dev_path_event1),
205 		"DEVPATH=%s/%s", sysname, handler1);
206 
207 	snprintf(dev_name1, sizeof(dev_name1),
208 		"DEVNAME=input/%s", handler1);
209 
210 
211 	snprintf(add_msg_event2, sizeof(add_msg_event2),
212 		"add@%s/%s", sysname, handler2);
213 
214 	snprintf(rem_msg_event2, sizeof(rem_msg_event2),
215 		"remove@%s/%s", sysname, handler2);
216 
217 	snprintf(dev_path_event2, sizeof(dev_path_event2),
218 		"DEVPATH=%s/%s", sysname, handler2);
219 
220 	snprintf(dev_name2, sizeof(dev_name2),
221 		"DEVNAME=input/%s", handler2);
222 
223 	free(sysname);
224 	free(handlers);
225 
226 	pid = SAFE_FORK();
227 	if (!pid) {
228 		wait_for_uevents(fd, uevents);
229 		exit(0);
230 	}
231 
232 	SAFE_CLOSE(fd);
233 	wait_for_pid(pid);
234 }
235 
236 static struct tst_test test = {
237 	.test_all = verify_uevent,
238 	.forks_child = 1,
239 	.needs_checkpoints = 1,
240 	.needs_drivers = (const char *const[]) {
241 		"uinput",
242 		NULL
243 	},
244 	.needs_root = 1,
245 };
246