]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
ba6929f6 | 2 | |
07630cea | 3 | #include <errno.h> |
07630cea | 4 | #include <poll.h> |
ba6929f6 | 5 | |
b4bbcaa9 TA |
6 | #include "libudev.h" |
7 | ||
b5efdb8a | 8 | #include "alloc-util.h" |
e39b4d25 | 9 | #include "device-monitor-private.h" |
23c457a7 YW |
10 | #include "device-private.h" |
11 | #include "device-util.h" | |
0f2d351f | 12 | #include "io-util.h" |
3782454c | 13 | #include "libudev-device-internal.h" |
07630cea | 14 | #include "string-util.h" |
ba6929f6 | 15 | |
ce1d6d7f KS |
16 | /** |
17 | * SECTION:libudev-monitor | |
18 | * @short_description: device event source | |
19 | * | |
20 | * Connects to a device event source. | |
21 | */ | |
22 | ||
ce1d6d7f KS |
23 | /** |
24 | * udev_monitor: | |
25 | * | |
50579295 | 26 | * Opaque object handling an event source. |
ce1d6d7f | 27 | */ |
ba6929f6 | 28 | struct udev_monitor { |
912541b0 | 29 | struct udev *udev; |
3c6ac219 | 30 | unsigned n_ref; |
e39b4d25 | 31 | sd_device_monitor *monitor; |
ba6929f6 KS |
32 | }; |
33 | ||
e39b4d25 YW |
34 | static MonitorNetlinkGroup monitor_netlink_group_from_string(const char *name) { |
35 | if (!name) | |
36 | return MONITOR_GROUP_NONE; | |
37 | if (streq(name, "udev")) | |
38 | return MONITOR_GROUP_UDEV; | |
39 | if (streq(name, "kernel")) | |
40 | return MONITOR_GROUP_KERNEL; | |
41 | return _MONITOR_NETLINK_GROUP_INVALID; | |
44daf75d TG |
42 | } |
43 | ||
c84954e8 YW |
44 | /** |
45 | * udev_monitor_new_from_netlink: | |
46 | * @udev: udev library context | |
47 | * @name: name of event source | |
48 | * | |
49 | * Create new udev monitor and connect to a specified event | |
50 | * source. Valid sources identifiers are "udev" and "kernel". | |
51 | * | |
52 | * Applications should usually not connect directly to the | |
5238e957 | 53 | * "kernel" events, because the devices might not be usable |
c84954e8 YW |
54 | * at that time, before udev has configured them, and created |
55 | * device nodes. Accessing devices at the same time as udev, | |
56 | * might result in unpredictable behavior. The "udev" events | |
57 | * are sent out after udev has finished its event processing, | |
58 | * all rules have been processed, and needed device nodes are | |
59 | * created. | |
60 | * | |
61 | * The initial refcount is 1, and needs to be decremented to | |
62 | * release the resources of the udev monitor. | |
63 | * | |
64 | * Returns: a new udev monitor, or #NULL, in case of an error | |
65 | **/ | |
66 | _public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) { | |
e39b4d25 | 67 | _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; |
5ea78a39 | 68 | struct udev_monitor *udev_monitor; |
e39b4d25 | 69 | MonitorNetlinkGroup g; |
5e1e4c24 YW |
70 | int r; |
71 | ||
e39b4d25 | 72 | g = monitor_netlink_group_from_string(name); |
fd05c424 YW |
73 | if (g < 0) |
74 | return_with_errno(NULL, EINVAL); | |
912541b0 | 75 | |
c84954e8 | 76 | r = device_monitor_new_full(&m, g, -1); |
fd05c424 YW |
77 | if (r < 0) |
78 | return_with_errno(NULL, r); | |
912541b0 | 79 | |
5e1e4c24 | 80 | udev_monitor = new(struct udev_monitor, 1); |
fd05c424 YW |
81 | if (!udev_monitor) |
82 | return_with_errno(NULL, ENOMEM); | |
5e1e4c24 YW |
83 | |
84 | *udev_monitor = (struct udev_monitor) { | |
85 | .udev = udev, | |
86 | .n_ref = 1, | |
e39b4d25 | 87 | .monitor = TAKE_PTR(m), |
5e1e4c24 YW |
88 | }; |
89 | ||
5ea78a39 | 90 | return udev_monitor; |
1c7047ea KS |
91 | } |
92 | ||
ce1d6d7f KS |
93 | /** |
94 | * udev_monitor_filter_update: | |
95 | * @udev_monitor: monitor | |
96 | * | |
50579295 KS |
97 | * Update the installed socket filter. This is only needed, |
98 | * if the filter was removed or changed. | |
ce1d6d7f KS |
99 | * |
100 | * Returns: 0 on success, otherwise a negative error value. | |
101 | */ | |
759d9f3f | 102 | _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) { |
759d9f3f | 103 | assert_return(udev_monitor, -EINVAL); |
912541b0 | 104 | |
e39b4d25 | 105 | return sd_device_monitor_filter_update(udev_monitor->monitor); |
e14bdd88 KS |
106 | } |
107 | ||
ce1d6d7f KS |
108 | /** |
109 | * udev_monitor_enable_receiving: | |
110 | * @udev_monitor: the monitor which should receive events | |
111 | * | |
112 | * Binds the @udev_monitor socket to the event source. | |
113 | * | |
114 | * Returns: 0 on success, otherwise a negative error value. | |
115 | */ | |
e38242b0 | 116 | _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) { |
e38242b0 YW |
117 | assert_return(udev_monitor, -EINVAL); |
118 | ||
e39b4d25 | 119 | return device_monitor_enable_receiving(udev_monitor->monitor); |
ba6929f6 KS |
120 | } |
121 | ||
f712894d KS |
122 | /** |
123 | * udev_monitor_set_receive_buffer_size: | |
124 | * @udev_monitor: the monitor which should receive events | |
125 | * @size: the size in bytes | |
126 | * | |
127 | * Set the size of the kernel socket buffer. This call needs the | |
128 | * appropriate privileges to succeed. | |
129 | * | |
130 | * Returns: 0 on success, otherwise -1 on error. | |
131 | */ | |
7f9e0395 YW |
132 | _public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) { |
133 | assert_return(udev_monitor, -EINVAL); | |
134 | ||
e39b4d25 | 135 | return sd_device_monitor_set_receive_buffer_size(udev_monitor->monitor, (size_t) size); |
cb25a958 KS |
136 | } |
137 | ||
3c6ac219 YW |
138 | static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor) { |
139 | assert(udev_monitor); | |
140 | ||
e39b4d25 | 141 | sd_device_monitor_unref(udev_monitor->monitor); |
3c6ac219 YW |
142 | return mfree(udev_monitor); |
143 | } | |
144 | ||
7d8787b3 KS |
145 | /** |
146 | * udev_monitor_ref: | |
147 | * @udev_monitor: udev monitor | |
148 | * | |
149 | * Take a reference of a udev monitor. | |
150 | * | |
151 | * Returns: the passed udev monitor | |
152 | **/ | |
ba6929f6 | 153 | |
7d8787b3 KS |
154 | /** |
155 | * udev_monitor_unref: | |
156 | * @udev_monitor: udev monitor | |
157 | * | |
ff109b8d | 158 | * Drop a reference of a udev monitor. If the refcount reaches zero, |
be7de409 | 159 | * the bound socket will be closed, and the resources of the monitor |
7d8787b3 KS |
160 | * will be released. |
161 | * | |
725d7e6c | 162 | * Returns: #NULL |
7d8787b3 | 163 | **/ |
3c6ac219 | 164 | DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor, udev_monitor, udev_monitor_free); |
ba6929f6 | 165 | |
7d8787b3 KS |
166 | /** |
167 | * udev_monitor_get_udev: | |
168 | * @udev_monitor: udev monitor | |
169 | * | |
b98fd840 | 170 | * Retrieve the udev library context the monitor was created with. |
7d8787b3 KS |
171 | * |
172 | * Returns: the udev library context | |
173 | **/ | |
7f9e0395 YW |
174 | _public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) { |
175 | assert_return(udev_monitor, NULL); | |
176 | ||
912541b0 | 177 | return udev_monitor->udev; |
ba6929f6 KS |
178 | } |
179 | ||
7d8787b3 KS |
180 | /** |
181 | * udev_monitor_get_fd: | |
182 | * @udev_monitor: udev monitor | |
183 | * | |
184 | * Retrieve the socket file descriptor associated with the monitor. | |
185 | * | |
186 | * Returns: the socket file descriptor | |
187 | **/ | |
7f9e0395 YW |
188 | _public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) { |
189 | assert_return(udev_monitor, -EINVAL); | |
190 | ||
e39b4d25 | 191 | return device_monitor_get_fd(udev_monitor->monitor); |
ba6929f6 KS |
192 | } |
193 | ||
c84954e8 | 194 | static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) { |
23c457a7 | 195 | int r; |
ba6929f6 | 196 | |
e39b4d25 | 197 | assert(udev_monitor); |
23c457a7 | 198 | assert(ret); |
912541b0 | 199 | |
23c457a7 YW |
200 | for (;;) { |
201 | /* r == 0 means a device is received but it does not pass the current filter. */ | |
e39b4d25 | 202 | r = device_monitor_receive_device(udev_monitor->monitor, ret); |
23c457a7 YW |
203 | if (r != 0) |
204 | return r; | |
205 | ||
206 | for (;;) { | |
0f2d351f LP |
207 | /* Wait for next message */ |
208 | r = fd_wait_for_event(device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0); | |
1d61d70a YW |
209 | if (r == -EINTR) |
210 | continue; | |
211 | if (r < 0) | |
0f2d351f | 212 | return r; |
dad28bff | 213 | if (r == 0) |
23c457a7 YW |
214 | return -EAGAIN; |
215 | ||
0f2d351f | 216 | /* Receive next message */ |
23c457a7 YW |
217 | break; |
218 | } | |
219 | } | |
ba6929f6 | 220 | } |
9925ab04 | 221 | |
23c457a7 YW |
222 | /** |
223 | * udev_monitor_receive_device: | |
224 | * @udev_monitor: udev monitor | |
225 | * | |
226 | * Receive data from the udev monitor socket, allocate a new udev | |
227 | * device, fill in the received data, and return the device. | |
228 | * | |
229 | * Only socket connections with uid=0 are accepted. | |
230 | * | |
231 | * The monitor socket is by default set to NONBLOCK. A variant of poll() on | |
232 | * the file descriptor returned by udev_monitor_get_fd() should to be used to | |
233 | * wake up when new devices arrive, or alternatively the file descriptor | |
234 | * switched into blocking mode. | |
235 | * | |
236 | * The initial refcount is 1, and needs to be decremented to | |
237 | * release the resources of the udev device. | |
238 | * | |
239 | * Returns: a new udev device, or #NULL, in case of an error | |
240 | **/ | |
241 | _public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) { | |
242 | _cleanup_(sd_device_unrefp) sd_device *device = NULL; | |
243 | int r; | |
3782454c | 244 | |
23c457a7 | 245 | assert_return(udev_monitor, NULL); |
3782454c | 246 | |
23c457a7 | 247 | r = udev_monitor_receive_sd_device(udev_monitor, &device); |
fd05c424 YW |
248 | if (r < 0) |
249 | return_with_errno(NULL, r); | |
3782454c | 250 | |
23c457a7 | 251 | return udev_device_new(udev_monitor->udev, device); |
3782454c YW |
252 | } |
253 | ||
ce1d6d7f KS |
254 | /** |
255 | * udev_monitor_filter_add_match_subsystem_devtype: | |
256 | * @udev_monitor: the monitor | |
257 | * @subsystem: the subsystem value to match the incoming devices against | |
214a6c79 | 258 | * @devtype: the devtype value to match the incoming devices against |
ce1d6d7f | 259 | * |
50579295 | 260 | * This filter is efficiently executed inside the kernel, and libudev subscribers |
28460195 KS |
261 | * will usually not be woken up for devices which do not match. |
262 | * | |
ce1d6d7f KS |
263 | * The filter must be installed before the monitor is switched to listening mode. |
264 | * | |
265 | * Returns: 0 on success, otherwise a negative error value. | |
266 | */ | |
759d9f3f | 267 | _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) { |
0f4b6e59 ZJS |
268 | int r; |
269 | ||
759d9f3f | 270 | assert_return(udev_monitor, -EINVAL); |
759d9f3f | 271 | |
0f4b6e59 ZJS |
272 | r = sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor->monitor, subsystem, devtype); |
273 | return r < 0 ? r : 0; | |
e14bdd88 | 274 | } |
08a7a795 | 275 | |
28460195 KS |
276 | /** |
277 | * udev_monitor_filter_add_match_tag: | |
278 | * @udev_monitor: the monitor | |
279 | * @tag: the name of a tag | |
280 | * | |
50579295 | 281 | * This filter is efficiently executed inside the kernel, and libudev subscribers |
28460195 KS |
282 | * will usually not be woken up for devices which do not match. |
283 | * | |
284 | * The filter must be installed before the monitor is switched to listening mode. | |
285 | * | |
286 | * Returns: 0 on success, otherwise a negative error value. | |
287 | */ | |
759d9f3f | 288 | _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) { |
0f4b6e59 ZJS |
289 | int r; |
290 | ||
759d9f3f | 291 | assert_return(udev_monitor, -EINVAL); |
759d9f3f | 292 | |
0f4b6e59 ZJS |
293 | r = sd_device_monitor_filter_add_match_tag(udev_monitor->monitor, tag); |
294 | return r < 0 ? r : 0; | |
28460195 KS |
295 | } |
296 | ||
ce1d6d7f KS |
297 | /** |
298 | * udev_monitor_filter_remove: | |
299 | * @udev_monitor: monitor | |
300 | * | |
301 | * Remove all filters from monitor. | |
302 | * | |
303 | * Returns: 0 on success, otherwise a negative error value. | |
304 | */ | |
759d9f3f | 305 | _public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) { |
759d9f3f YW |
306 | assert_return(udev_monitor, -EINVAL); |
307 | ||
e39b4d25 | 308 | return sd_device_monitor_filter_remove(udev_monitor->monitor); |
08a7a795 | 309 | } |