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