Line data Source code
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 10 : _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
69 20 : _cleanup_free_ struct udev_enumerate *udev_enumerate = NULL;
70 : struct udev_enumerate *ret;
71 : int r;
72 :
73 10 : assert_return_errno(udev, NULL, EINVAL);
74 :
75 10 : udev_enumerate = new0(struct udev_enumerate, 1);
76 10 : if (!udev_enumerate) {
77 0 : errno = ENOMEM;
78 0 : return NULL;
79 : }
80 :
81 10 : r = sd_device_enumerator_new(&udev_enumerate->enumerator);
82 10 : if (r < 0) {
83 0 : errno = -r;
84 0 : return NULL;
85 : }
86 :
87 10 : r = sd_device_enumerator_allow_uninitialized(udev_enumerate->enumerator);
88 10 : if (r < 0) {
89 0 : errno = -r;
90 0 : return NULL;
91 : }
92 :
93 10 : udev_enumerate->refcount = 1;
94 10 : udev_enumerate->udev = udev;
95 :
96 10 : udev_list_init(udev, &udev_enumerate->devices_list, false);
97 :
98 10 : ret = udev_enumerate;
99 10 : udev_enumerate = NULL;
100 :
101 10 : 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 0 : _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
113 0 : if (udev_enumerate)
114 0 : udev_enumerate->refcount ++;
115 :
116 0 : 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 10 : _public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) {
129 10 : if (udev_enumerate && (-- udev_enumerate->refcount) == 0) {
130 10 : udev_list_cleanup(&udev_enumerate->devices_list);
131 10 : sd_device_enumerator_unref(udev_enumerate->enumerator);
132 10 : free(udev_enumerate);
133 : }
134 :
135 10 : 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 0 : _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
147 0 : assert_return_errno(udev_enumerate, NULL, EINVAL);
148 :
149 0 : 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 10 : _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
161 10 : assert_return_errno(udev_enumerate, NULL, EINVAL);
162 :
163 10 : if (!udev_enumerate->devices_uptodate) {
164 : sd_device *device;
165 :
166 10 : udev_list_cleanup(&udev_enumerate->devices_list);
167 :
168 220 : FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) {
169 : const char *syspath;
170 : int r;
171 :
172 210 : r = sd_device_get_syspath(device, &syspath);
173 210 : if (r < 0) {
174 0 : errno = -r;
175 0 : return NULL;
176 : }
177 :
178 210 : udev_list_entry_add(&udev_enumerate->devices_list, syspath, NULL);
179 : }
180 :
181 10 : udev_enumerate->devices_uptodate = true;
182 : }
183 :
184 10 : 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 0 : _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
197 0 : assert_return(udev_enumerate, -EINVAL);
198 :
199 0 : if (!subsystem)
200 0 : return 0;
201 :
202 0 : 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 0 : _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
215 0 : assert_return(udev_enumerate, -EINVAL);
216 :
217 0 : if (!subsystem)
218 0 : return 0;
219 :
220 0 : 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 0 : _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
234 0 : assert_return(udev_enumerate, -EINVAL);
235 :
236 0 : if (!sysattr)
237 0 : return 0;
238 :
239 0 : 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 0 : _public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
253 0 : assert_return(udev_enumerate, -EINVAL);
254 :
255 0 : if (!sysattr)
256 0 : return 0;
257 :
258 0 : 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 0 : _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
272 0 : assert_return(udev_enumerate, -EINVAL);
273 :
274 0 : if (!property)
275 0 : return 0;
276 :
277 0 : 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 10 : _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
290 10 : assert_return(udev_enumerate, -EINVAL);
291 :
292 10 : if (!tag)
293 0 : return 0;
294 :
295 10 : 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 0 : _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
312 0 : assert_return(udev_enumerate, -EINVAL);
313 :
314 0 : if (!parent)
315 0 : return 0;
316 :
317 0 : 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 10 : _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
339 10 : assert_return(udev_enumerate, -EINVAL);
340 :
341 10 : 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 0 : _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
354 0 : assert_return(udev_enumerate, -EINVAL);
355 :
356 0 : if (!sysname)
357 0 : return 0;
358 :
359 0 : 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 0 : _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
372 0 : _cleanup_device_unref_ sd_device *device = NULL;
373 : int r;
374 :
375 0 : assert_return(udev_enumerate, -EINVAL);
376 :
377 0 : if (!syspath)
378 0 : return 0;
379 :
380 0 : r = sd_device_new_from_syspath(&device, syspath);
381 0 : if (r < 0)
382 0 : return r;
383 :
384 0 : r = device_enumerator_add_device(udev_enumerate->enumerator, device);
385 0 : if (r < 0)
386 0 : return r;
387 :
388 0 : 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 10 : _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
401 10 : assert_return(udev_enumerate, -EINVAL);
402 :
403 10 : 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 0 : _public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
415 0 : assert_return(udev_enumerate, -EINVAL);
416 :
417 0 : return device_enumerator_scan_subsystems(udev_enumerate->enumerator);
418 : }
|