]>
Commit | Line | Data |
---|---|---|
a032b68d | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
663996b3 | 2 | |
663996b3 | 3 | #include <dirent.h> |
db2df898 | 4 | #include <errno.h> |
663996b3 MS |
5 | #include <fnmatch.h> |
6 | #include <stdbool.h> | |
db2df898 MP |
7 | #include <stddef.h> |
8 | #include <stdio.h> | |
9 | #include <stdlib.h> | |
10 | #include <string.h> | |
663996b3 | 11 | #include <sys/stat.h> |
663996b3 MS |
12 | |
13 | #include "libudev.h" | |
e3bff60a | 14 | #include "sd-device.h" |
e3bff60a | 15 | |
db2df898 MP |
16 | #include "alloc-util.h" |
17 | #include "device-enumerator-private.h" | |
18 | #include "device-util.h" | |
19 | #include "libudev-device-internal.h" | |
f2dec872 | 20 | #include "libudev-list-internal.h" |
663996b3 MS |
21 | |
22 | /** | |
23 | * SECTION:libudev-enumerate | |
24 | * @short_description: lookup and sort sys devices | |
25 | * | |
26 | * Lookup devices in the sys filesystem, filter devices by properties, | |
27 | * and return a sorted list of devices. | |
28 | */ | |
29 | ||
663996b3 MS |
30 | /** |
31 | * udev_enumerate: | |
32 | * | |
33 | * Opaque object representing one device lookup/sort context. | |
34 | */ | |
35 | struct udev_enumerate { | |
36 | struct udev *udev; | |
6e866b33 | 37 | unsigned n_ref; |
f2dec872 | 38 | struct udev_list *devices_list; |
663996b3 | 39 | bool devices_uptodate:1; |
e3bff60a MP |
40 | |
41 | sd_device_enumerator *enumerator; | |
663996b3 MS |
42 | }; |
43 | ||
44 | /** | |
45 | * udev_enumerate_new: | |
46 | * @udev: udev library context | |
47 | * | |
48 | * Create an enumeration context to scan /sys. | |
49 | * | |
50 | * Returns: an enumeration context. | |
51 | **/ | |
e3bff60a | 52 | _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) { |
6e866b33 | 53 | _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; |
f2dec872 | 54 | _cleanup_(udev_list_freep) struct udev_list *list = NULL; |
6e866b33 | 55 | struct udev_enumerate *udev_enumerate; |
e3bff60a MP |
56 | int r; |
57 | ||
6e866b33 MB |
58 | r = sd_device_enumerator_new(&e); |
59 | if (r < 0) | |
60 | return_with_errno(NULL, r); | |
663996b3 | 61 | |
6e866b33 MB |
62 | r = sd_device_enumerator_allow_uninitialized(e); |
63 | if (r < 0) | |
64 | return_with_errno(NULL, r); | |
e3bff60a | 65 | |
f2dec872 BR |
66 | list = udev_list_new(false); |
67 | if (!list) | |
68 | return_with_errno(NULL, ENOMEM); | |
69 | ||
6e866b33 MB |
70 | udev_enumerate = new(struct udev_enumerate, 1); |
71 | if (!udev_enumerate) | |
72 | return_with_errno(NULL, ENOMEM); | |
e3bff60a | 73 | |
6e866b33 MB |
74 | *udev_enumerate = (struct udev_enumerate) { |
75 | .udev = udev, | |
76 | .n_ref = 1, | |
77 | .enumerator = TAKE_PTR(e), | |
f2dec872 | 78 | .devices_list = TAKE_PTR(list), |
6e866b33 | 79 | }; |
e3bff60a | 80 | |
6e866b33 MB |
81 | return udev_enumerate; |
82 | } | |
83 | ||
84 | static struct udev_enumerate *udev_enumerate_free(struct udev_enumerate *udev_enumerate) { | |
85 | assert(udev_enumerate); | |
e3bff60a | 86 | |
f2dec872 | 87 | udev_list_free(udev_enumerate->devices_list); |
6e866b33 MB |
88 | sd_device_enumerator_unref(udev_enumerate->enumerator); |
89 | return mfree(udev_enumerate); | |
663996b3 MS |
90 | } |
91 | ||
92 | /** | |
93 | * udev_enumerate_ref: | |
94 | * @udev_enumerate: context | |
95 | * | |
67bbd050 | 96 | * Take a reference of an enumeration context. |
663996b3 MS |
97 | * |
98 | * Returns: the passed enumeration context | |
99 | **/ | |
663996b3 MS |
100 | |
101 | /** | |
102 | * udev_enumerate_unref: | |
103 | * @udev_enumerate: context | |
104 | * | |
105 | * Drop a reference of an enumeration context. If the refcount reaches zero, | |
106 | * all resources of the enumeration context will be released. | |
107 | * | |
60f067b4 | 108 | * Returns: #NULL |
663996b3 | 109 | **/ |
6e866b33 | 110 | DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_enumerate, udev_enumerate, udev_enumerate_free); |
663996b3 MS |
111 | |
112 | /** | |
113 | * udev_enumerate_get_udev: | |
114 | * @udev_enumerate: context | |
115 | * | |
116 | * Get the udev library context. | |
117 | * | |
118 | * Returns: a pointer to the context. | |
119 | */ | |
e3bff60a MP |
120 | _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) { |
121 | assert_return_errno(udev_enumerate, NULL, EINVAL); | |
663996b3 | 122 | |
e3bff60a | 123 | return udev_enumerate->udev; |
663996b3 MS |
124 | } |
125 | ||
126 | /** | |
127 | * udev_enumerate_get_list_entry: | |
128 | * @udev_enumerate: context | |
129 | * | |
130 | * Get the first entry of the sorted list of device paths. | |
131 | * | |
132 | * Returns: a udev_list_entry. | |
133 | */ | |
e3bff60a | 134 | _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) { |
f5e65279 MB |
135 | struct udev_list_entry *e; |
136 | ||
e3bff60a MP |
137 | assert_return_errno(udev_enumerate, NULL, EINVAL); |
138 | ||
663996b3 | 139 | if (!udev_enumerate->devices_uptodate) { |
e3bff60a | 140 | sd_device *device; |
663996b3 | 141 | |
f2dec872 | 142 | udev_list_cleanup(udev_enumerate->devices_list); |
663996b3 | 143 | |
e3bff60a MP |
144 | FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) { |
145 | const char *syspath; | |
146 | int r; | |
663996b3 | 147 | |
e3bff60a | 148 | r = sd_device_get_syspath(device, &syspath); |
6e866b33 MB |
149 | if (r < 0) |
150 | return_with_errno(NULL, r); | |
663996b3 | 151 | |
f2dec872 | 152 | if (!udev_list_entry_add(udev_enumerate->devices_list, syspath, NULL)) |
6e866b33 | 153 | return_with_errno(NULL, ENOMEM); |
663996b3 MS |
154 | } |
155 | ||
663996b3 MS |
156 | udev_enumerate->devices_uptodate = true; |
157 | } | |
e3bff60a | 158 | |
f2dec872 | 159 | e = udev_list_get_entry(udev_enumerate->devices_list); |
f5e65279 | 160 | if (!e) |
6e866b33 | 161 | return_with_errno(NULL, ENODATA); |
f5e65279 MB |
162 | |
163 | return e; | |
663996b3 MS |
164 | } |
165 | ||
166 | /** | |
167 | * udev_enumerate_add_match_subsystem: | |
168 | * @udev_enumerate: context | |
169 | * @subsystem: filter for a subsystem of the device to include in the list | |
170 | * | |
171 | * Match only devices belonging to a certain kernel subsystem. | |
172 | * | |
173 | * Returns: 0 on success, otherwise a negative error value. | |
174 | */ | |
e3bff60a | 175 | _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) { |
f2dec872 BR |
176 | int r; |
177 | ||
e3bff60a MP |
178 | assert_return(udev_enumerate, -EINVAL); |
179 | ||
86f210e9 MP |
180 | if (!subsystem) |
181 | return 0; | |
182 | ||
f2dec872 BR |
183 | r = sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, true); |
184 | if (r < 0) | |
185 | return r; | |
186 | ||
187 | udev_enumerate->devices_uptodate = false; | |
188 | return 0; | |
663996b3 MS |
189 | } |
190 | ||
191 | /** | |
192 | * udev_enumerate_add_nomatch_subsystem: | |
193 | * @udev_enumerate: context | |
194 | * @subsystem: filter for a subsystem of the device to exclude from the list | |
195 | * | |
196 | * Match only devices not belonging to a certain kernel subsystem. | |
197 | * | |
198 | * Returns: 0 on success, otherwise a negative error value. | |
199 | */ | |
e3bff60a | 200 | _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) { |
f2dec872 BR |
201 | int r; |
202 | ||
e3bff60a MP |
203 | assert_return(udev_enumerate, -EINVAL); |
204 | ||
86f210e9 MP |
205 | if (!subsystem) |
206 | return 0; | |
207 | ||
f2dec872 BR |
208 | r = sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, false); |
209 | if (r < 0) | |
210 | return r; | |
211 | ||
212 | udev_enumerate->devices_uptodate = false; | |
213 | return 0; | |
663996b3 MS |
214 | } |
215 | ||
216 | /** | |
217 | * udev_enumerate_add_match_sysattr: | |
218 | * @udev_enumerate: context | |
219 | * @sysattr: filter for a sys attribute at the device to include in the list | |
220 | * @value: optional value of the sys attribute | |
221 | * | |
222 | * Match only devices with a certain /sys device attribute. | |
223 | * | |
224 | * Returns: 0 on success, otherwise a negative error value. | |
225 | */ | |
e3bff60a | 226 | _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) { |
f2dec872 BR |
227 | int r; |
228 | ||
e3bff60a MP |
229 | assert_return(udev_enumerate, -EINVAL); |
230 | ||
86f210e9 MP |
231 | if (!sysattr) |
232 | return 0; | |
233 | ||
f2dec872 BR |
234 | r = sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true); |
235 | if (r < 0) | |
236 | return r; | |
237 | ||
238 | udev_enumerate->devices_uptodate = false; | |
239 | return 0; | |
663996b3 MS |
240 | } |
241 | ||
242 | /** | |
243 | * udev_enumerate_add_nomatch_sysattr: | |
244 | * @udev_enumerate: context | |
245 | * @sysattr: filter for a sys attribute at the device to exclude from the list | |
246 | * @value: optional value of the sys attribute | |
247 | * | |
248 | * Match only devices not having a certain /sys device attribute. | |
249 | * | |
250 | * Returns: 0 on success, otherwise a negative error value. | |
251 | */ | |
e3bff60a | 252 | _public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) { |
f2dec872 BR |
253 | int r; |
254 | ||
e3bff60a | 255 | assert_return(udev_enumerate, -EINVAL); |
663996b3 | 256 | |
86f210e9 MP |
257 | if (!sysattr) |
258 | return 0; | |
259 | ||
f2dec872 BR |
260 | r = sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false); |
261 | if (r < 0) | |
262 | return r; | |
263 | ||
264 | udev_enumerate->devices_uptodate = false; | |
265 | return 0; | |
663996b3 MS |
266 | } |
267 | ||
268 | /** | |
269 | * udev_enumerate_add_match_property: | |
270 | * @udev_enumerate: context | |
271 | * @property: filter for a property of the device to include in the list | |
272 | * @value: value of the property | |
273 | * | |
274 | * Match only devices with a certain property. | |
275 | * | |
276 | * Returns: 0 on success, otherwise a negative error value. | |
277 | */ | |
e3bff60a | 278 | _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) { |
f2dec872 BR |
279 | int r; |
280 | ||
e3bff60a MP |
281 | assert_return(udev_enumerate, -EINVAL); |
282 | ||
86f210e9 MP |
283 | if (!property) |
284 | return 0; | |
285 | ||
f2dec872 BR |
286 | r = sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value); |
287 | if (r < 0) | |
288 | return r; | |
289 | ||
290 | udev_enumerate->devices_uptodate = false; | |
291 | return 0; | |
663996b3 MS |
292 | } |
293 | ||
294 | /** | |
295 | * udev_enumerate_add_match_tag: | |
296 | * @udev_enumerate: context | |
297 | * @tag: filter for a tag of the device to include in the list | |
298 | * | |
299 | * Match only devices with a certain tag. | |
300 | * | |
301 | * Returns: 0 on success, otherwise a negative error value. | |
302 | */ | |
e3bff60a | 303 | _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) { |
f2dec872 BR |
304 | int r; |
305 | ||
e3bff60a MP |
306 | assert_return(udev_enumerate, -EINVAL); |
307 | ||
86f210e9 MP |
308 | if (!tag) |
309 | return 0; | |
310 | ||
f2dec872 BR |
311 | r = sd_device_enumerator_add_match_tag(udev_enumerate->enumerator, tag); |
312 | if (r < 0) | |
313 | return r; | |
314 | ||
315 | udev_enumerate->devices_uptodate = false; | |
316 | return 0; | |
663996b3 MS |
317 | } |
318 | ||
319 | /** | |
320 | * udev_enumerate_add_match_parent: | |
321 | * @udev_enumerate: context | |
322 | * @parent: parent device where to start searching | |
323 | * | |
324 | * Return the devices on the subtree of one given device. The parent | |
325 | * itself is included in the list. | |
326 | * | |
663996b3 MS |
327 | * Returns: 0 on success, otherwise a negative error value. |
328 | */ | |
e3bff60a | 329 | _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) { |
f2dec872 BR |
330 | int r; |
331 | ||
e3bff60a MP |
332 | assert_return(udev_enumerate, -EINVAL); |
333 | ||
334 | if (!parent) | |
663996b3 | 335 | return 0; |
e3bff60a | 336 | |
f2dec872 BR |
337 | r = sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, udev_device_get_sd_device(parent)); |
338 | if (r < 0) | |
339 | return r; | |
340 | ||
341 | udev_enumerate->devices_uptodate = false; | |
342 | return 0; | |
663996b3 MS |
343 | } |
344 | ||
345 | /** | |
346 | * udev_enumerate_add_match_is_initialized: | |
347 | * @udev_enumerate: context | |
348 | * | |
349 | * Match only devices which udev has set up already. This makes | |
350 | * sure, that the device node permissions and context are properly set | |
351 | * and that network devices are fully renamed. | |
352 | * | |
353 | * Usually, devices which are found in the kernel but not already | |
354 | * handled by udev, have still pending events. Services should subscribe | |
355 | * to monitor events and wait for these devices to become ready, instead | |
356 | * of using uninitialized devices. | |
357 | * | |
358 | * For now, this will not affect devices which do not have a device node | |
359 | * and are not network interfaces. | |
360 | * | |
361 | * Returns: 0 on success, otherwise a negative error value. | |
362 | */ | |
e3bff60a | 363 | _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) { |
f2dec872 BR |
364 | int r; |
365 | ||
e3bff60a MP |
366 | assert_return(udev_enumerate, -EINVAL); |
367 | ||
f5caa8fa | 368 | r = device_enumerator_add_match_is_initialized(udev_enumerate->enumerator, MATCH_INITIALIZED_COMPAT); |
f2dec872 BR |
369 | if (r < 0) |
370 | return r; | |
371 | ||
372 | udev_enumerate->devices_uptodate = false; | |
373 | return 0; | |
663996b3 MS |
374 | } |
375 | ||
376 | /** | |
377 | * udev_enumerate_add_match_sysname: | |
378 | * @udev_enumerate: context | |
379 | * @sysname: filter for the name of the device to include in the list | |
380 | * | |
381 | * Match only devices with a given /sys device name. | |
382 | * | |
383 | * Returns: 0 on success, otherwise a negative error value. | |
384 | */ | |
e3bff60a | 385 | _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) { |
f2dec872 BR |
386 | int r; |
387 | ||
e3bff60a | 388 | assert_return(udev_enumerate, -EINVAL); |
663996b3 | 389 | |
86f210e9 MP |
390 | if (!sysname) |
391 | return 0; | |
392 | ||
f2dec872 BR |
393 | r = sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname); |
394 | if (r < 0) | |
395 | return r; | |
396 | ||
397 | udev_enumerate->devices_uptodate = false; | |
398 | return 0; | |
663996b3 MS |
399 | } |
400 | ||
401 | /** | |
402 | * udev_enumerate_add_syspath: | |
403 | * @udev_enumerate: context | |
404 | * @syspath: path of a device | |
405 | * | |
406 | * Add a device to the list of devices, to retrieve it back sorted in dependency order. | |
407 | * | |
408 | * Returns: 0 on success, otherwise a negative error value. | |
409 | */ | |
e3bff60a | 410 | _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) { |
4c89c718 | 411 | _cleanup_(sd_device_unrefp) sd_device *device = NULL; |
e3bff60a | 412 | int r; |
663996b3 | 413 | |
e3bff60a | 414 | assert_return(udev_enumerate, -EINVAL); |
663996b3 | 415 | |
e3bff60a MP |
416 | if (!syspath) |
417 | return 0; | |
663996b3 | 418 | |
e3bff60a MP |
419 | r = sd_device_new_from_syspath(&device, syspath); |
420 | if (r < 0) | |
421 | return r; | |
663996b3 | 422 | |
e3bff60a MP |
423 | r = device_enumerator_add_device(udev_enumerate->enumerator, device); |
424 | if (r < 0) | |
425 | return r; | |
663996b3 | 426 | |
f2dec872 | 427 | udev_enumerate->devices_uptodate = false; |
663996b3 MS |
428 | return 0; |
429 | } | |
430 | ||
431 | /** | |
432 | * udev_enumerate_scan_devices: | |
433 | * @udev_enumerate: udev enumeration context | |
434 | * | |
435 | * Scan /sys for all devices which match the given filters. No matches | |
436 | * will return all currently available devices. | |
437 | * | |
438 | * Returns: 0 on success, otherwise a negative error value. | |
439 | **/ | |
e3bff60a MP |
440 | _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) { |
441 | assert_return(udev_enumerate, -EINVAL); | |
663996b3 | 442 | |
e3bff60a | 443 | return device_enumerator_scan_devices(udev_enumerate->enumerator); |
663996b3 MS |
444 | } |
445 | ||
446 | /** | |
447 | * udev_enumerate_scan_subsystems: | |
448 | * @udev_enumerate: udev enumeration context | |
449 | * | |
450 | * Scan /sys for all kernel subsystems, including buses, classes, drivers. | |
451 | * | |
452 | * Returns: 0 on success, otherwise a negative error value. | |
453 | **/ | |
e3bff60a MP |
454 | _public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) { |
455 | assert_return(udev_enumerate, -EINVAL); | |
456 | ||
457 | return device_enumerator_scan_subsystems(udev_enumerate->enumerator); | |
663996b3 | 458 | } |