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