1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 #include "libudev-list-internal.h"
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 
30 /**
31  * udev_enumerate:
32  *
33  * Opaque object representing one device lookup/sort context.
34  */
35 struct udev_enumerate {
36         struct udev *udev;
37         unsigned n_ref;
38         struct udev_list *devices_list;
39         bool devices_uptodate:1;
40 
41         sd_device_enumerator *enumerator;
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  **/
udev_enumerate_new(struct udev * udev)52 _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
53         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
54         _cleanup_(udev_list_freep) struct udev_list *list = NULL;
55         struct udev_enumerate *udev_enumerate;
56         int r;
57 
58         r = sd_device_enumerator_new(&e);
59         if (r < 0)
60                 return_with_errno(NULL, r);
61 
62         r = sd_device_enumerator_allow_uninitialized(e);
63         if (r < 0)
64                 return_with_errno(NULL, r);
65 
66         list = udev_list_new(false);
67         if (!list)
68                 return_with_errno(NULL, ENOMEM);
69 
70         udev_enumerate = new(struct udev_enumerate, 1);
71         if (!udev_enumerate)
72                 return_with_errno(NULL, ENOMEM);
73 
74         *udev_enumerate = (struct udev_enumerate) {
75                 .udev = udev,
76                 .n_ref = 1,
77                 .enumerator = TAKE_PTR(e),
78                 .devices_list = TAKE_PTR(list),
79         };
80 
81         return udev_enumerate;
82 }
83 
udev_enumerate_free(struct udev_enumerate * udev_enumerate)84 static struct udev_enumerate *udev_enumerate_free(struct udev_enumerate *udev_enumerate) {
85         assert(udev_enumerate);
86 
87         udev_list_free(udev_enumerate->devices_list);
88         sd_device_enumerator_unref(udev_enumerate->enumerator);
89         return mfree(udev_enumerate);
90 }
91 
92 /**
93  * udev_enumerate_ref:
94  * @udev_enumerate: context
95  *
96  * Take a reference of an enumeration context.
97  *
98  * Returns: the passed enumeration context
99  **/
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  *
108  * Returns: #NULL
109  **/
110 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_enumerate, udev_enumerate, udev_enumerate_free);
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  */
udev_enumerate_get_udev(struct udev_enumerate * udev_enumerate)120 _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
121         assert_return_errno(udev_enumerate, NULL, EINVAL);
122 
123         return udev_enumerate->udev;
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  */
udev_enumerate_get_list_entry(struct udev_enumerate * udev_enumerate)134 _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
135         struct udev_list_entry *e;
136 
137         assert_return_errno(udev_enumerate, NULL, EINVAL);
138 
139         if (!udev_enumerate->devices_uptodate) {
140                 sd_device *device;
141 
142                 udev_list_cleanup(udev_enumerate->devices_list);
143 
144                 FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) {
145                         const char *syspath;
146                         int r;
147 
148                         r = sd_device_get_syspath(device, &syspath);
149                         if (r < 0)
150                                 return_with_errno(NULL, r);
151 
152                         if (!udev_list_entry_add(udev_enumerate->devices_list, syspath, NULL))
153                                 return_with_errno(NULL, ENOMEM);
154                 }
155 
156                 udev_enumerate->devices_uptodate = true;
157         }
158 
159         e = udev_list_get_entry(udev_enumerate->devices_list);
160         if (!e)
161                 return_with_errno(NULL, ENODATA);
162 
163         return e;
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  */
udev_enumerate_add_match_subsystem(struct udev_enumerate * udev_enumerate,const char * subsystem)175 _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
176         int r;
177 
178         assert_return(udev_enumerate, -EINVAL);
179 
180         if (!subsystem)
181                 return 0;
182 
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;
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  */
udev_enumerate_add_nomatch_subsystem(struct udev_enumerate * udev_enumerate,const char * subsystem)200 _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
201         int r;
202 
203         assert_return(udev_enumerate, -EINVAL);
204 
205         if (!subsystem)
206                 return 0;
207 
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;
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  */
udev_enumerate_add_match_sysattr(struct udev_enumerate * udev_enumerate,const char * sysattr,const char * value)226 _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
227         int r;
228 
229         assert_return(udev_enumerate, -EINVAL);
230 
231         if (!sysattr)
232                 return 0;
233 
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;
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  */
udev_enumerate_add_nomatch_sysattr(struct udev_enumerate * udev_enumerate,const char * sysattr,const char * value)252 _public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
253         int r;
254 
255         assert_return(udev_enumerate, -EINVAL);
256 
257         if (!sysattr)
258                 return 0;
259 
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;
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  */
udev_enumerate_add_match_property(struct udev_enumerate * udev_enumerate,const char * property,const char * value)278 _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
279         int r;
280 
281         assert_return(udev_enumerate, -EINVAL);
282 
283         if (!property)
284                 return 0;
285 
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;
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  */
udev_enumerate_add_match_tag(struct udev_enumerate * udev_enumerate,const char * tag)303 _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
304         int r;
305 
306         assert_return(udev_enumerate, -EINVAL);
307 
308         if (!tag)
309                 return 0;
310 
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;
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  *
327  * Returns: 0 on success, otherwise a negative error value.
328  */
udev_enumerate_add_match_parent(struct udev_enumerate * udev_enumerate,struct udev_device * parent)329 _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
330         int r;
331 
332         assert_return(udev_enumerate, -EINVAL);
333 
334         if (!parent)
335                 return 0;
336 
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;
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  */
udev_enumerate_add_match_is_initialized(struct udev_enumerate * udev_enumerate)363 _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
364         int r;
365 
366         assert_return(udev_enumerate, -EINVAL);
367 
368         r = device_enumerator_add_match_is_initialized(udev_enumerate->enumerator, MATCH_INITIALIZED_COMPAT);
369         if (r < 0)
370                 return r;
371 
372         udev_enumerate->devices_uptodate = false;
373         return 0;
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  */
udev_enumerate_add_match_sysname(struct udev_enumerate * udev_enumerate,const char * sysname)385 _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
386         int r;
387 
388         assert_return(udev_enumerate, -EINVAL);
389 
390         if (!sysname)
391                 return 0;
392 
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;
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  */
udev_enumerate_add_syspath(struct udev_enumerate * udev_enumerate,const char * syspath)410 _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
411         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
412         int r;
413 
414         assert_return(udev_enumerate, -EINVAL);
415 
416         if (!syspath)
417                 return 0;
418 
419         r = sd_device_new_from_syspath(&device, syspath);
420         if (r < 0)
421                 return r;
422 
423         r = device_enumerator_add_device(udev_enumerate->enumerator, device);
424         if (r < 0)
425                 return r;
426 
427         udev_enumerate->devices_uptodate = false;
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  **/
udev_enumerate_scan_devices(struct udev_enumerate * udev_enumerate)440 _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
441         assert_return(udev_enumerate, -EINVAL);
442 
443         return device_enumerator_scan_devices(udev_enumerate->enumerator);
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  **/
udev_enumerate_scan_subsystems(struct udev_enumerate * udev_enumerate)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);
458 }
459