]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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" | |
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 | |
52 | * "kernel" events, because the devices might not be useable | |
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 | **/ | |
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 | |
c84954e8 | 75 | r = device_monitor_new_full(&m, g, -1); |
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 | * | |
111 | * Binds the @udev_monitor socket to the event source. | |
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) { |
e38242b0 YW |
116 | assert_return(udev_monitor, -EINVAL); |
117 | ||
e39b4d25 | 118 | return device_monitor_enable_receiving(udev_monitor->monitor); |
ba6929f6 KS |
119 | } |
120 | ||
f712894d KS |
121 | /** |
122 | * udev_monitor_set_receive_buffer_size: | |
123 | * @udev_monitor: the monitor which should receive events | |
124 | * @size: the size in bytes | |
125 | * | |
126 | * Set the size of the kernel socket buffer. This call needs the | |
127 | * appropriate privileges to succeed. | |
128 | * | |
129 | * Returns: 0 on success, otherwise -1 on error. | |
130 | */ | |
7f9e0395 YW |
131 | _public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) { |
132 | assert_return(udev_monitor, -EINVAL); | |
133 | ||
e39b4d25 | 134 | return sd_device_monitor_set_receive_buffer_size(udev_monitor->monitor, (size_t) size); |
cb25a958 KS |
135 | } |
136 | ||
3c6ac219 YW |
137 | static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor) { |
138 | assert(udev_monitor); | |
139 | ||
e39b4d25 | 140 | sd_device_monitor_unref(udev_monitor->monitor); |
3c6ac219 YW |
141 | return mfree(udev_monitor); |
142 | } | |
143 | ||
7d8787b3 KS |
144 | /** |
145 | * udev_monitor_ref: | |
146 | * @udev_monitor: udev monitor | |
147 | * | |
148 | * Take a reference of a udev monitor. | |
149 | * | |
150 | * Returns: the passed udev monitor | |
151 | **/ | |
ba6929f6 | 152 | |
7d8787b3 KS |
153 | /** |
154 | * udev_monitor_unref: | |
155 | * @udev_monitor: udev monitor | |
156 | * | |
ff109b8d | 157 | * Drop a reference of a udev monitor. If the refcount reaches zero, |
be7de409 | 158 | * the bound socket will be closed, and the resources of the monitor |
7d8787b3 KS |
159 | * will be released. |
160 | * | |
725d7e6c | 161 | * Returns: #NULL |
7d8787b3 | 162 | **/ |
3c6ac219 | 163 | DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor, udev_monitor, udev_monitor_free); |
ba6929f6 | 164 | |
7d8787b3 KS |
165 | /** |
166 | * udev_monitor_get_udev: | |
167 | * @udev_monitor: udev monitor | |
168 | * | |
b98fd840 | 169 | * Retrieve the udev library context the monitor was created with. |
7d8787b3 KS |
170 | * |
171 | * Returns: the udev library context | |
172 | **/ | |
7f9e0395 YW |
173 | _public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) { |
174 | assert_return(udev_monitor, NULL); | |
175 | ||
912541b0 | 176 | return udev_monitor->udev; |
ba6929f6 KS |
177 | } |
178 | ||
7d8787b3 KS |
179 | /** |
180 | * udev_monitor_get_fd: | |
181 | * @udev_monitor: udev monitor | |
182 | * | |
183 | * Retrieve the socket file descriptor associated with the monitor. | |
184 | * | |
185 | * Returns: the socket file descriptor | |
186 | **/ | |
7f9e0395 YW |
187 | _public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) { |
188 | assert_return(udev_monitor, -EINVAL); | |
189 | ||
e39b4d25 | 190 | return device_monitor_get_fd(udev_monitor->monitor); |
ba6929f6 KS |
191 | } |
192 | ||
c84954e8 | 193 | static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) { |
e39b4d25 | 194 | struct pollfd pfd; |
23c457a7 | 195 | int r; |
ba6929f6 | 196 | |
e39b4d25 | 197 | assert(udev_monitor); |
23c457a7 | 198 | assert(ret); |
912541b0 | 199 | |
e39b4d25 YW |
200 | pfd = (struct pollfd) { |
201 | .fd = device_monitor_get_fd(udev_monitor->monitor), | |
23c457a7 YW |
202 | .events = POLLIN, |
203 | }; | |
912541b0 | 204 | |
23c457a7 YW |
205 | for (;;) { |
206 | /* r == 0 means a device is received but it does not pass the current filter. */ | |
e39b4d25 | 207 | r = device_monitor_receive_device(udev_monitor->monitor, ret); |
23c457a7 YW |
208 | if (r != 0) |
209 | return r; | |
210 | ||
211 | for (;;) { | |
212 | /* wait next message */ | |
213 | r = poll(&pfd, 1, 0); | |
214 | if (r < 0) { | |
215 | if (IN_SET(errno, EINTR, EAGAIN)) | |
216 | continue; | |
217 | ||
218 | return -errno; | |
219 | } else if (r == 0) | |
220 | return -EAGAIN; | |
221 | ||
222 | /* receive next message */ | |
223 | break; | |
224 | } | |
225 | } | |
ba6929f6 | 226 | } |
9925ab04 | 227 | |
23c457a7 YW |
228 | /** |
229 | * udev_monitor_receive_device: | |
230 | * @udev_monitor: udev monitor | |
231 | * | |
232 | * Receive data from the udev monitor socket, allocate a new udev | |
233 | * device, fill in the received data, and return the device. | |
234 | * | |
235 | * Only socket connections with uid=0 are accepted. | |
236 | * | |
237 | * The monitor socket is by default set to NONBLOCK. A variant of poll() on | |
238 | * the file descriptor returned by udev_monitor_get_fd() should to be used to | |
239 | * wake up when new devices arrive, or alternatively the file descriptor | |
240 | * switched into blocking mode. | |
241 | * | |
242 | * The initial refcount is 1, and needs to be decremented to | |
243 | * release the resources of the udev device. | |
244 | * | |
245 | * Returns: a new udev device, or #NULL, in case of an error | |
246 | **/ | |
247 | _public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) { | |
248 | _cleanup_(sd_device_unrefp) sd_device *device = NULL; | |
249 | int r; | |
3782454c | 250 | |
23c457a7 | 251 | assert_return(udev_monitor, NULL); |
3782454c | 252 | |
23c457a7 | 253 | r = udev_monitor_receive_sd_device(udev_monitor, &device); |
fd05c424 YW |
254 | if (r < 0) |
255 | return_with_errno(NULL, r); | |
3782454c | 256 | |
23c457a7 | 257 | return udev_device_new(udev_monitor->udev, device); |
3782454c YW |
258 | } |
259 | ||
ce1d6d7f KS |
260 | /** |
261 | * udev_monitor_filter_add_match_subsystem_devtype: | |
262 | * @udev_monitor: the monitor | |
263 | * @subsystem: the subsystem value to match the incoming devices against | |
214a6c79 | 264 | * @devtype: the devtype value to match the incoming devices against |
ce1d6d7f | 265 | * |
50579295 | 266 | * This filter is efficiently executed inside the kernel, and libudev subscribers |
28460195 KS |
267 | * will usually not be woken up for devices which do not match. |
268 | * | |
ce1d6d7f KS |
269 | * The filter must be installed before the monitor is switched to listening mode. |
270 | * | |
271 | * Returns: 0 on success, otherwise a negative error value. | |
272 | */ | |
759d9f3f | 273 | _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) { |
759d9f3f | 274 | assert_return(udev_monitor, -EINVAL); |
759d9f3f | 275 | |
e39b4d25 | 276 | return sd_device_monitor_filter_add_match_subsystem_devtype(udev_monitor->monitor, subsystem, devtype); |
e14bdd88 | 277 | } |
08a7a795 | 278 | |
28460195 KS |
279 | /** |
280 | * udev_monitor_filter_add_match_tag: | |
281 | * @udev_monitor: the monitor | |
282 | * @tag: the name of a tag | |
283 | * | |
50579295 | 284 | * This filter is efficiently executed inside the kernel, and libudev subscribers |
28460195 KS |
285 | * will usually not be woken up for devices which do not match. |
286 | * | |
287 | * The filter must be installed before the monitor is switched to listening mode. | |
288 | * | |
289 | * Returns: 0 on success, otherwise a negative error value. | |
290 | */ | |
759d9f3f | 291 | _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) { |
759d9f3f | 292 | assert_return(udev_monitor, -EINVAL); |
759d9f3f | 293 | |
e39b4d25 | 294 | return sd_device_monitor_filter_add_match_tag(udev_monitor->monitor, tag); |
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 | } |