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