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