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