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