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