]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libudev/libudev-enumerate.c
libudev-enumerate: use structured initializer
[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 struct udev_enumerate *udev_enumerate;
54 int r;
55
56 r = sd_device_enumerator_new(&e);
57 if (r < 0) {
58 errno = -r;
59 return NULL;
60 }
61
62 r = sd_device_enumerator_allow_uninitialized(e);
63 if (r < 0) {
64 errno = -r;
65 return NULL;
66 }
67
68 udev_enumerate = new(struct udev_enumerate, 1);
69 if (!udev_enumerate) {
70 errno = ENOMEM;
71 return NULL;
72 }
73
74 *udev_enumerate = (struct udev_enumerate) {
75 .udev = udev,
76 .n_ref = 1,
77 .enumerator = TAKE_PTR(e),
78 };
79
80 udev_list_init(udev, &udev_enumerate->devices_list, false);
81
82 return udev_enumerate;
83 }
84
85 static struct udev_enumerate *udev_enumerate_free(struct udev_enumerate *udev_enumerate) {
86 assert(udev_enumerate);
87
88 udev_list_cleanup(&udev_enumerate->devices_list);
89 sd_device_enumerator_unref(udev_enumerate->enumerator);
90 return mfree(udev_enumerate);
91 }
92
93 /**
94 * udev_enumerate_ref:
95 * @udev_enumerate: context
96 *
97 * Take a reference of a enumeration context.
98 *
99 * Returns: the passed enumeration context
100 **/
101
102 /**
103 * udev_enumerate_unref:
104 * @udev_enumerate: context
105 *
106 * Drop a reference of an enumeration context. If the refcount reaches zero,
107 * all resources of the enumeration context will be released.
108 *
109 * Returns: #NULL
110 **/
111 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_enumerate, udev_enumerate, udev_enumerate_free);
112
113 /**
114 * udev_enumerate_get_udev:
115 * @udev_enumerate: context
116 *
117 * Get the udev library context.
118 *
119 * Returns: a pointer to the context.
120 */
121 _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
122 assert_return_errno(udev_enumerate, NULL, EINVAL);
123
124 return udev_enumerate->udev;
125 }
126
127 /**
128 * udev_enumerate_get_list_entry:
129 * @udev_enumerate: context
130 *
131 * Get the first entry of the sorted list of device paths.
132 *
133 * Returns: a udev_list_entry.
134 */
135 _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
136 struct udev_list_entry *e;
137
138 assert_return_errno(udev_enumerate, NULL, EINVAL);
139
140 if (!udev_enumerate->devices_uptodate) {
141 sd_device *device;
142
143 udev_list_cleanup(&udev_enumerate->devices_list);
144
145 FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) {
146 const char *syspath;
147 int r;
148
149 r = sd_device_get_syspath(device, &syspath);
150 if (r < 0) {
151 errno = -r;
152 return NULL;
153 }
154
155 udev_list_entry_add(&udev_enumerate->devices_list, syspath, NULL);
156 }
157
158 udev_enumerate->devices_uptodate = true;
159 }
160
161 e = udev_list_get_entry(&udev_enumerate->devices_list);
162 if (!e)
163 errno = ENODATA;
164
165 return e;
166 }
167
168 /**
169 * udev_enumerate_add_match_subsystem:
170 * @udev_enumerate: context
171 * @subsystem: filter for a subsystem of the device to include in the list
172 *
173 * Match only devices belonging to a certain kernel subsystem.
174 *
175 * Returns: 0 on success, otherwise a negative error value.
176 */
177 _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
178 assert_return(udev_enumerate, -EINVAL);
179
180 if (!subsystem)
181 return 0;
182
183 return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, true);
184 }
185
186 /**
187 * udev_enumerate_add_nomatch_subsystem:
188 * @udev_enumerate: context
189 * @subsystem: filter for a subsystem of the device to exclude from the list
190 *
191 * Match only devices not belonging to a certain kernel subsystem.
192 *
193 * Returns: 0 on success, otherwise a negative error value.
194 */
195 _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
196 assert_return(udev_enumerate, -EINVAL);
197
198 if (!subsystem)
199 return 0;
200
201 return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, false);
202 }
203
204 /**
205 * udev_enumerate_add_match_sysattr:
206 * @udev_enumerate: context
207 * @sysattr: filter for a sys attribute at the device to include in the list
208 * @value: optional value of the sys attribute
209 *
210 * Match only devices with a certain /sys device attribute.
211 *
212 * Returns: 0 on success, otherwise a negative error value.
213 */
214 _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
215 assert_return(udev_enumerate, -EINVAL);
216
217 if (!sysattr)
218 return 0;
219
220 return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true);
221 }
222
223 /**
224 * udev_enumerate_add_nomatch_sysattr:
225 * @udev_enumerate: context
226 * @sysattr: filter for a sys attribute at the device to exclude from the list
227 * @value: optional value of the sys attribute
228 *
229 * Match only devices not having a certain /sys device attribute.
230 *
231 * Returns: 0 on success, otherwise a negative error value.
232 */
233 _public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
234 assert_return(udev_enumerate, -EINVAL);
235
236 if (!sysattr)
237 return 0;
238
239 return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false);
240 }
241
242 /**
243 * udev_enumerate_add_match_property:
244 * @udev_enumerate: context
245 * @property: filter for a property of the device to include in the list
246 * @value: value of the property
247 *
248 * Match only devices with a certain property.
249 *
250 * Returns: 0 on success, otherwise a negative error value.
251 */
252 _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
253 assert_return(udev_enumerate, -EINVAL);
254
255 if (!property)
256 return 0;
257
258 return sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value);
259 }
260
261 /**
262 * udev_enumerate_add_match_tag:
263 * @udev_enumerate: context
264 * @tag: filter for a tag of the device to include in the list
265 *
266 * Match only devices with a certain tag.
267 *
268 * Returns: 0 on success, otherwise a negative error value.
269 */
270 _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
271 assert_return(udev_enumerate, -EINVAL);
272
273 if (!tag)
274 return 0;
275
276 return sd_device_enumerator_add_match_tag(udev_enumerate->enumerator, tag);
277 }
278
279 /**
280 * udev_enumerate_add_match_parent:
281 * @udev_enumerate: context
282 * @parent: parent device where to start searching
283 *
284 * Return the devices on the subtree of one given device. The parent
285 * itself is included in the list.
286 *
287 * A reference for the device is held until the udev_enumerate context
288 * is cleaned up.
289 *
290 * Returns: 0 on success, otherwise a negative error value.
291 */
292 _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
293 assert_return(udev_enumerate, -EINVAL);
294
295 if (!parent)
296 return 0;
297
298 return sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, parent->device);
299 }
300
301 /**
302 * udev_enumerate_add_match_is_initialized:
303 * @udev_enumerate: context
304 *
305 * Match only devices which udev has set up already. This makes
306 * sure, that the device node permissions and context are properly set
307 * and that network devices are fully renamed.
308 *
309 * Usually, devices which are found in the kernel but not already
310 * handled by udev, have still pending events. Services should subscribe
311 * to monitor events and wait for these devices to become ready, instead
312 * of using uninitialized devices.
313 *
314 * For now, this will not affect devices which do not have a device node
315 * and are not network interfaces.
316 *
317 * Returns: 0 on success, otherwise a negative error value.
318 */
319 _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
320 assert_return(udev_enumerate, -EINVAL);
321
322 return device_enumerator_add_match_is_initialized(udev_enumerate->enumerator);
323 }
324
325 /**
326 * udev_enumerate_add_match_sysname:
327 * @udev_enumerate: context
328 * @sysname: filter for the name of the device to include in the list
329 *
330 * Match only devices with a given /sys device name.
331 *
332 * Returns: 0 on success, otherwise a negative error value.
333 */
334 _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
335 assert_return(udev_enumerate, -EINVAL);
336
337 if (!sysname)
338 return 0;
339
340 return sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname);
341 }
342
343 /**
344 * udev_enumerate_add_syspath:
345 * @udev_enumerate: context
346 * @syspath: path of a device
347 *
348 * Add a device to the list of devices, to retrieve it back sorted in dependency order.
349 *
350 * Returns: 0 on success, otherwise a negative error value.
351 */
352 _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
353 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
354 int r;
355
356 assert_return(udev_enumerate, -EINVAL);
357
358 if (!syspath)
359 return 0;
360
361 r = sd_device_new_from_syspath(&device, syspath);
362 if (r < 0)
363 return r;
364
365 r = device_enumerator_add_device(udev_enumerate->enumerator, device);
366 if (r < 0)
367 return r;
368
369 return 0;
370 }
371
372 /**
373 * udev_enumerate_scan_devices:
374 * @udev_enumerate: udev enumeration context
375 *
376 * Scan /sys for all devices which match the given filters. No matches
377 * will return all currently available devices.
378 *
379 * Returns: 0 on success, otherwise a negative error value.
380 **/
381 _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
382 assert_return(udev_enumerate, -EINVAL);
383
384 return device_enumerator_scan_devices(udev_enumerate->enumerator);
385 }
386
387 /**
388 * udev_enumerate_scan_subsystems:
389 * @udev_enumerate: udev enumeration context
390 *
391 * Scan /sys for all kernel subsystems, including buses, classes, drivers.
392 *
393 * Returns: 0 on success, otherwise a negative error value.
394 **/
395 _public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
396 assert_return(udev_enumerate, -EINVAL);
397
398 return device_enumerator_scan_subsystems(udev_enumerate->enumerator);
399 }