]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libudev/libudev-enumerate.c
481c90df105a7a77736153fbb1a3f45864139b86
[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 assert_return(udev_enumerate, -EINVAL);
176
177 if (!subsystem)
178 return 0;
179
180 return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, true);
181 }
182
183 /**
184 * udev_enumerate_add_nomatch_subsystem:
185 * @udev_enumerate: context
186 * @subsystem: filter for a subsystem of the device to exclude from the list
187 *
188 * Match only devices not belonging to a certain kernel subsystem.
189 *
190 * Returns: 0 on success, otherwise a negative error value.
191 */
192 _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
193 assert_return(udev_enumerate, -EINVAL);
194
195 if (!subsystem)
196 return 0;
197
198 return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, false);
199 }
200
201 /**
202 * udev_enumerate_add_match_sysattr:
203 * @udev_enumerate: context
204 * @sysattr: filter for a sys attribute at the device to include in the list
205 * @value: optional value of the sys attribute
206 *
207 * Match only devices with a certain /sys device attribute.
208 *
209 * Returns: 0 on success, otherwise a negative error value.
210 */
211 _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
212 assert_return(udev_enumerate, -EINVAL);
213
214 if (!sysattr)
215 return 0;
216
217 return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true);
218 }
219
220 /**
221 * udev_enumerate_add_nomatch_sysattr:
222 * @udev_enumerate: context
223 * @sysattr: filter for a sys attribute at the device to exclude from the list
224 * @value: optional value of the sys attribute
225 *
226 * Match only devices not having a certain /sys device attribute.
227 *
228 * Returns: 0 on success, otherwise a negative error value.
229 */
230 _public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
231 assert_return(udev_enumerate, -EINVAL);
232
233 if (!sysattr)
234 return 0;
235
236 return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false);
237 }
238
239 /**
240 * udev_enumerate_add_match_property:
241 * @udev_enumerate: context
242 * @property: filter for a property of the device to include in the list
243 * @value: value of the property
244 *
245 * Match only devices with a certain property.
246 *
247 * Returns: 0 on success, otherwise a negative error value.
248 */
249 _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
250 assert_return(udev_enumerate, -EINVAL);
251
252 if (!property)
253 return 0;
254
255 return sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value);
256 }
257
258 /**
259 * udev_enumerate_add_match_tag:
260 * @udev_enumerate: context
261 * @tag: filter for a tag of the device to include in the list
262 *
263 * Match only devices with a certain tag.
264 *
265 * Returns: 0 on success, otherwise a negative error value.
266 */
267 _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
268 assert_return(udev_enumerate, -EINVAL);
269
270 if (!tag)
271 return 0;
272
273 return sd_device_enumerator_add_match_tag(udev_enumerate->enumerator, tag);
274 }
275
276 /**
277 * udev_enumerate_add_match_parent:
278 * @udev_enumerate: context
279 * @parent: parent device where to start searching
280 *
281 * Return the devices on the subtree of one given device. The parent
282 * itself is included in the list.
283 *
284 * Returns: 0 on success, otherwise a negative error value.
285 */
286 _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
287 assert_return(udev_enumerate, -EINVAL);
288
289 if (!parent)
290 return 0;
291
292 return sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, parent->device);
293 }
294
295 /**
296 * udev_enumerate_add_match_is_initialized:
297 * @udev_enumerate: context
298 *
299 * Match only devices which udev has set up already. This makes
300 * sure, that the device node permissions and context are properly set
301 * and that network devices are fully renamed.
302 *
303 * Usually, devices which are found in the kernel but not already
304 * handled by udev, have still pending events. Services should subscribe
305 * to monitor events and wait for these devices to become ready, instead
306 * of using uninitialized devices.
307 *
308 * For now, this will not affect devices which do not have a device node
309 * and are not network interfaces.
310 *
311 * Returns: 0 on success, otherwise a negative error value.
312 */
313 _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
314 assert_return(udev_enumerate, -EINVAL);
315
316 return device_enumerator_add_match_is_initialized(udev_enumerate->enumerator);
317 }
318
319 /**
320 * udev_enumerate_add_match_sysname:
321 * @udev_enumerate: context
322 * @sysname: filter for the name of the device to include in the list
323 *
324 * Match only devices with a given /sys device name.
325 *
326 * Returns: 0 on success, otherwise a negative error value.
327 */
328 _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
329 assert_return(udev_enumerate, -EINVAL);
330
331 if (!sysname)
332 return 0;
333
334 return sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname);
335 }
336
337 /**
338 * udev_enumerate_add_syspath:
339 * @udev_enumerate: context
340 * @syspath: path of a device
341 *
342 * Add a device to the list of devices, to retrieve it back sorted in dependency order.
343 *
344 * Returns: 0 on success, otherwise a negative error value.
345 */
346 _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
347 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
348 int r;
349
350 assert_return(udev_enumerate, -EINVAL);
351
352 if (!syspath)
353 return 0;
354
355 r = sd_device_new_from_syspath(&device, syspath);
356 if (r < 0)
357 return r;
358
359 r = device_enumerator_add_device(udev_enumerate->enumerator, device);
360 if (r < 0)
361 return r;
362
363 return 0;
364 }
365
366 /**
367 * udev_enumerate_scan_devices:
368 * @udev_enumerate: udev enumeration context
369 *
370 * Scan /sys for all devices which match the given filters. No matches
371 * will return all currently available devices.
372 *
373 * Returns: 0 on success, otherwise a negative error value.
374 **/
375 _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
376 assert_return(udev_enumerate, -EINVAL);
377
378 return device_enumerator_scan_devices(udev_enumerate->enumerator);
379 }
380
381 /**
382 * udev_enumerate_scan_subsystems:
383 * @udev_enumerate: udev enumeration context
384 *
385 * Scan /sys for all kernel subsystems, including buses, classes, drivers.
386 *
387 * Returns: 0 on success, otherwise a negative error value.
388 **/
389 _public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
390 assert_return(udev_enumerate, -EINVAL);
391
392 return device_enumerator_scan_subsystems(udev_enumerate->enumerator);
393 }