xref: /aosp_15_r20/external/ltp/testcases/kernel/uevents/uevent.h (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (C) 2019 Cyril Hrubis <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker  */
5*49cdfc7eSAndroid Build Coastguard Worker 
6*49cdfc7eSAndroid Build Coastguard Worker #ifndef UEVENT_H__
7*49cdfc7eSAndroid Build Coastguard Worker #define UEVENT_H__
8*49cdfc7eSAndroid Build Coastguard Worker 
9*49cdfc7eSAndroid Build Coastguard Worker #include "tst_netlink.h"
10*49cdfc7eSAndroid Build Coastguard Worker 
11*49cdfc7eSAndroid Build Coastguard Worker /*
12*49cdfc7eSAndroid Build Coastguard Worker  * There are two broadcast groups defined for the NETLINK_KOBJECT_UEVENT. The
13*49cdfc7eSAndroid Build Coastguard Worker  * primary consument of the KERNEL group is udev which handles the hotplug
14*49cdfc7eSAndroid Build Coastguard Worker  * events and then, once udev does it's magic the events are rebroadcasted to
15*49cdfc7eSAndroid Build Coastguard Worker  * the UDEV group which is consumed by various daemons in the userspace.
16*49cdfc7eSAndroid Build Coastguard Worker  */
17*49cdfc7eSAndroid Build Coastguard Worker enum monitor_netlink_group {
18*49cdfc7eSAndroid Build Coastguard Worker 	MONITOR_GROUP_NONE,
19*49cdfc7eSAndroid Build Coastguard Worker 	MONITOR_GROUP_KERNEL,
20*49cdfc7eSAndroid Build Coastguard Worker 	MONITOR_GROUP_UDEV,
21*49cdfc7eSAndroid Build Coastguard Worker };
22*49cdfc7eSAndroid Build Coastguard Worker 
23*49cdfc7eSAndroid Build Coastguard Worker /*
24*49cdfc7eSAndroid Build Coastguard Worker  * The messages received from the NETLINK_KOBJECT_UEVENT socket are stored as a
25*49cdfc7eSAndroid Build Coastguard Worker  * sequence of a null-terminated strings. First in the buffer is a summary of a
26*49cdfc7eSAndroid Build Coastguard Worker  * action i.e. "$ACTION@$DEVPATH" which is then followed by a bunch of
27*49cdfc7eSAndroid Build Coastguard Worker  * key-value pairs.
28*49cdfc7eSAndroid Build Coastguard Worker  *
29*49cdfc7eSAndroid Build Coastguard Worker  * For example attaching a file to loopback device generates event:
30*49cdfc7eSAndroid Build Coastguard Worker  *
31*49cdfc7eSAndroid Build Coastguard Worker  * "change@/devices/virtual/block/loop0\0
32*49cdfc7eSAndroid Build Coastguard Worker  *  ACTION=change\0
33*49cdfc7eSAndroid Build Coastguard Worker  *  DEVPATH=/devices/virtual/block/loop0\0
34*49cdfc7eSAndroid Build Coastguard Worker  *  SUBSYSTEM=block\0
35*49cdfc7eSAndroid Build Coastguard Worker  *  MAJOR=7\0
36*49cdfc7eSAndroid Build Coastguard Worker  *  MINOR=0\0
37*49cdfc7eSAndroid Build Coastguard Worker  *  DEVNAME=loop0\0
38*49cdfc7eSAndroid Build Coastguard Worker  *  DEVTYPE=disk\0
39*49cdfc7eSAndroid Build Coastguard Worker  *  SEQNUM=2677\0"
40*49cdfc7eSAndroid Build Coastguard Worker  */
41*49cdfc7eSAndroid Build Coastguard Worker 
42*49cdfc7eSAndroid Build Coastguard Worker /*
43*49cdfc7eSAndroid Build Coastguard Worker  * Prints uevent.
44*49cdfc7eSAndroid Build Coastguard Worker  */
print_uevent(const char * event,int len)45*49cdfc7eSAndroid Build Coastguard Worker static inline void print_uevent(const char *event, int len)
46*49cdfc7eSAndroid Build Coastguard Worker {
47*49cdfc7eSAndroid Build Coastguard Worker 	int consumed = 0;
48*49cdfc7eSAndroid Build Coastguard Worker 
49*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Got uevent:");
50*49cdfc7eSAndroid Build Coastguard Worker 
51*49cdfc7eSAndroid Build Coastguard Worker 	while (consumed < len) {
52*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "%s", event);
53*49cdfc7eSAndroid Build Coastguard Worker 		int l = strlen(event) + 1;
54*49cdfc7eSAndroid Build Coastguard Worker 		consumed += l;
55*49cdfc7eSAndroid Build Coastguard Worker 		event += l;
56*49cdfc7eSAndroid Build Coastguard Worker 	}
57*49cdfc7eSAndroid Build Coastguard Worker }
58*49cdfc7eSAndroid Build Coastguard Worker 
59*49cdfc7eSAndroid Build Coastguard Worker /*
60*49cdfc7eSAndroid Build Coastguard Worker  * Uevents read from the socket are matched against this description.
61*49cdfc7eSAndroid Build Coastguard Worker  *
62*49cdfc7eSAndroid Build Coastguard Worker  * The msg is the overall action description e.g.
63*49cdfc7eSAndroid Build Coastguard Worker  * "add@/class/input/input4/mouse1" which has to be matched exactly before we
64*49cdfc7eSAndroid Build Coastguard Worker  * event attempt to check the key-value pairs stored in the values array. The
65*49cdfc7eSAndroid Build Coastguard Worker  * event is considered to match if all key-value pairs in the values has been
66*49cdfc7eSAndroid Build Coastguard Worker  * found in the received event.
67*49cdfc7eSAndroid Build Coastguard Worker  */
68*49cdfc7eSAndroid Build Coastguard Worker struct uevent_desc {
69*49cdfc7eSAndroid Build Coastguard Worker 	const char *msg;
70*49cdfc7eSAndroid Build Coastguard Worker 	int value_cnt;
71*49cdfc7eSAndroid Build Coastguard Worker 	const char **values;
72*49cdfc7eSAndroid Build Coastguard Worker };
73*49cdfc7eSAndroid Build Coastguard Worker 
uevent_match(const char * event,int len,const struct uevent_desc * uevent)74*49cdfc7eSAndroid Build Coastguard Worker static inline int uevent_match(const char *event, int len,
75*49cdfc7eSAndroid Build Coastguard Worker                                const struct uevent_desc *uevent)
76*49cdfc7eSAndroid Build Coastguard Worker {
77*49cdfc7eSAndroid Build Coastguard Worker 	int consumed = 0;
78*49cdfc7eSAndroid Build Coastguard Worker 	int val_matches = 0;
79*49cdfc7eSAndroid Build Coastguard Worker 
80*49cdfc7eSAndroid Build Coastguard Worker 	if (memcmp(event, uevent->msg, strlen(uevent->msg)))
81*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
82*49cdfc7eSAndroid Build Coastguard Worker 
83*49cdfc7eSAndroid Build Coastguard Worker 	int l = strlen(event) + 1;
84*49cdfc7eSAndroid Build Coastguard Worker 
85*49cdfc7eSAndroid Build Coastguard Worker 	consumed += l;
86*49cdfc7eSAndroid Build Coastguard Worker 	event += l;
87*49cdfc7eSAndroid Build Coastguard Worker 
88*49cdfc7eSAndroid Build Coastguard Worker 	while (consumed < len) {
89*49cdfc7eSAndroid Build Coastguard Worker 		int i;
90*49cdfc7eSAndroid Build Coastguard Worker 		for (i = 0; i < uevent->value_cnt; i++) {
91*49cdfc7eSAndroid Build Coastguard Worker 			if (!strcmp(event, uevent->values[i])) {
92*49cdfc7eSAndroid Build Coastguard Worker 				val_matches++;
93*49cdfc7eSAndroid Build Coastguard Worker 				break;
94*49cdfc7eSAndroid Build Coastguard Worker 			}
95*49cdfc7eSAndroid Build Coastguard Worker 		}
96*49cdfc7eSAndroid Build Coastguard Worker 
97*49cdfc7eSAndroid Build Coastguard Worker 		l = strlen(event) + 1;
98*49cdfc7eSAndroid Build Coastguard Worker 		consumed += l;
99*49cdfc7eSAndroid Build Coastguard Worker 		event += l;
100*49cdfc7eSAndroid Build Coastguard Worker 	}
101*49cdfc7eSAndroid Build Coastguard Worker 
102*49cdfc7eSAndroid Build Coastguard Worker 	return val_matches == uevent->value_cnt;
103*49cdfc7eSAndroid Build Coastguard Worker }
104*49cdfc7eSAndroid Build Coastguard Worker 
open_uevent_netlink(void)105*49cdfc7eSAndroid Build Coastguard Worker static inline int open_uevent_netlink(void)
106*49cdfc7eSAndroid Build Coastguard Worker {
107*49cdfc7eSAndroid Build Coastguard Worker 	int fd;
108*49cdfc7eSAndroid Build Coastguard Worker 	struct sockaddr_nl nl_addr = {
109*49cdfc7eSAndroid Build Coastguard Worker 		.nl_family = AF_NETLINK,
110*49cdfc7eSAndroid Build Coastguard Worker 		.nl_groups = MONITOR_GROUP_KERNEL,
111*49cdfc7eSAndroid Build Coastguard Worker 	};
112*49cdfc7eSAndroid Build Coastguard Worker 
113*49cdfc7eSAndroid Build Coastguard Worker 	fd = SAFE_SOCKET(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
114*49cdfc7eSAndroid Build Coastguard Worker 
115*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_BIND(fd, (struct sockaddr *)&nl_addr, sizeof(nl_addr));
116*49cdfc7eSAndroid Build Coastguard Worker 
117*49cdfc7eSAndroid Build Coastguard Worker 	return fd;
118*49cdfc7eSAndroid Build Coastguard Worker }
119*49cdfc7eSAndroid Build Coastguard Worker 
120*49cdfc7eSAndroid Build Coastguard Worker /*
121*49cdfc7eSAndroid Build Coastguard Worker  * Reads events from uevent netlink socket until all expected events passed in
122*49cdfc7eSAndroid Build Coastguard Worker  * the uevent array are matched.
123*49cdfc7eSAndroid Build Coastguard Worker  */
wait_for_uevents(int fd,const struct uevent_desc * const uevents[])124*49cdfc7eSAndroid Build Coastguard Worker static inline void wait_for_uevents(int fd, const struct uevent_desc *const uevents[])
125*49cdfc7eSAndroid Build Coastguard Worker {
126*49cdfc7eSAndroid Build Coastguard Worker 	int i = 0;
127*49cdfc7eSAndroid Build Coastguard Worker 
128*49cdfc7eSAndroid Build Coastguard Worker 	while (1) {
129*49cdfc7eSAndroid Build Coastguard Worker 		int len;
130*49cdfc7eSAndroid Build Coastguard Worker 		char buf[4096];
131*49cdfc7eSAndroid Build Coastguard Worker 
132*49cdfc7eSAndroid Build Coastguard Worker 		len = recv(fd, &buf, sizeof(buf), 0);
133*49cdfc7eSAndroid Build Coastguard Worker 
134*49cdfc7eSAndroid Build Coastguard Worker 		if (len == 0)
135*49cdfc7eSAndroid Build Coastguard Worker 			continue;
136*49cdfc7eSAndroid Build Coastguard Worker 
137*49cdfc7eSAndroid Build Coastguard Worker 		print_uevent(buf, len);
138*49cdfc7eSAndroid Build Coastguard Worker 
139*49cdfc7eSAndroid Build Coastguard Worker 		if (uevent_match(buf, len, uevents[i])) {
140*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TPASS, "Got expected UEVENT");
141*49cdfc7eSAndroid Build Coastguard Worker 			if (!uevents[++i]) {
142*49cdfc7eSAndroid Build Coastguard Worker 				close(fd);
143*49cdfc7eSAndroid Build Coastguard Worker 				return;
144*49cdfc7eSAndroid Build Coastguard Worker 			}
145*49cdfc7eSAndroid Build Coastguard Worker 		}
146*49cdfc7eSAndroid Build Coastguard Worker 	}
147*49cdfc7eSAndroid Build Coastguard Worker }
148*49cdfc7eSAndroid Build Coastguard Worker 
149*49cdfc7eSAndroid Build Coastguard Worker /*
150*49cdfc7eSAndroid Build Coastguard Worker  * Waits 5 seconds for a child to exit, kills the child after a timeout.
151*49cdfc7eSAndroid Build Coastguard Worker  */
wait_for_pid(int pid)152*49cdfc7eSAndroid Build Coastguard Worker static inline void wait_for_pid(int pid)
153*49cdfc7eSAndroid Build Coastguard Worker {
154*49cdfc7eSAndroid Build Coastguard Worker 	int status, ret;
155*49cdfc7eSAndroid Build Coastguard Worker 	int retries = 5000;
156*49cdfc7eSAndroid Build Coastguard Worker 
157*49cdfc7eSAndroid Build Coastguard Worker 	do {
158*49cdfc7eSAndroid Build Coastguard Worker 		ret = waitpid(pid, &status, WNOHANG);
159*49cdfc7eSAndroid Build Coastguard Worker 		usleep(1000);
160*49cdfc7eSAndroid Build Coastguard Worker 	} while (ret == 0 && retries--);
161*49cdfc7eSAndroid Build Coastguard Worker 
162*49cdfc7eSAndroid Build Coastguard Worker 	if (ret == pid) {
163*49cdfc7eSAndroid Build Coastguard Worker 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
164*49cdfc7eSAndroid Build Coastguard Worker 			return;
165*49cdfc7eSAndroid Build Coastguard Worker 
166*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "Child exited with %s", tst_strstatus(status));
167*49cdfc7eSAndroid Build Coastguard Worker 	}
168*49cdfc7eSAndroid Build Coastguard Worker 
169*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_KILL(pid, SIGKILL);
170*49cdfc7eSAndroid Build Coastguard Worker 
171*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_WAITPID(pid, NULL, 0);
172*49cdfc7eSAndroid Build Coastguard Worker 
173*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TFAIL, "Did not get all expected UEVENTS");
174*49cdfc7eSAndroid Build Coastguard Worker }
175*49cdfc7eSAndroid Build Coastguard Worker 
176*49cdfc7eSAndroid Build Coastguard Worker #endif /* UEVENT_H__ */
177