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