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