]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
88a6477e KS |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2008-2012 Kay Sievers <kay@vrfy.org> | |
c32eb440 | 6 | Copyright 2015 Tom Gundersen <teg@jklm.no> |
88a6477e KS |
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 | ***/ | |
eb1f0e66 | 21 | |
eb1f0e66 | 22 | #include <dirent.h> |
07630cea | 23 | #include <errno.h> |
c97f839e | 24 | #include <fnmatch.h> |
871a36bd | 25 | #include <stdbool.h> |
07630cea LP |
26 | #include <stddef.h> |
27 | #include <stdio.h> | |
28 | #include <stdlib.h> | |
29 | #include <string.h> | |
eb1f0e66 KS |
30 | #include <sys/stat.h> |
31 | ||
b4bbcaa9 | 32 | #include "libudev.h" |
c32eb440 | 33 | #include "sd-device.h" |
c32eb440 | 34 | |
b5efdb8a | 35 | #include "alloc-util.h" |
07630cea LP |
36 | #include "device-enumerator-private.h" |
37 | #include "device-util.h" | |
38 | #include "libudev-device-internal.h" | |
eb1f0e66 | 39 | |
ce1d6d7f KS |
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, | |
a7c140c7 | 45 | * and return a sorted list of devices. |
ce1d6d7f KS |
46 | */ |
47 | ||
48 | /** | |
49 | * udev_enumerate: | |
50 | * | |
51 | * Opaque object representing one device lookup/sort context. | |
52 | */ | |
bf7ad0ea | 53 | struct udev_enumerate { |
912541b0 KS |
54 | struct udev *udev; |
55 | int refcount; | |
912541b0 | 56 | struct udev_list devices_list; |
912541b0 | 57 | bool devices_uptodate:1; |
c32eb440 TG |
58 | |
59 | sd_device_enumerator *enumerator; | |
bf7ad0ea KS |
60 | }; |
61 | ||
c97f839e KS |
62 | /** |
63 | * udev_enumerate_new: | |
64 | * @udev: udev library context | |
65 | * | |
21dbe43a KS |
66 | * Create an enumeration context to scan /sys. |
67 | * | |
68 | * Returns: an enumeration context. | |
c97f839e | 69 | **/ |
c32eb440 | 70 | _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) { |
dee5e0b6 TG |
71 | _cleanup_free_ struct udev_enumerate *udev_enumerate = NULL; |
72 | struct udev_enumerate *ret; | |
c32eb440 TG |
73 | int r; |
74 | ||
75 | assert_return_errno(udev, NULL, EINVAL); | |
c97f839e | 76 | |
955d98c9 | 77 | udev_enumerate = new0(struct udev_enumerate, 1); |
c32eb440 TG |
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) { | |
dee5e0b6 TG |
85 | errno = -r; |
86 | return NULL; | |
87 | } | |
88 | ||
89 | r = sd_device_enumerator_allow_uninitialized(udev_enumerate->enumerator); | |
90 | if (r < 0) { | |
c32eb440 | 91 | errno = -r; |
912541b0 | 92 | return NULL; |
c32eb440 TG |
93 | } |
94 | ||
912541b0 KS |
95 | udev_enumerate->refcount = 1; |
96 | udev_enumerate->udev = udev; | |
c32eb440 | 97 | |
912541b0 | 98 | udev_list_init(udev, &udev_enumerate->devices_list, false); |
c32eb440 | 99 | |
dee5e0b6 TG |
100 | ret = udev_enumerate; |
101 | udev_enumerate = NULL; | |
102 | ||
103 | return ret; | |
c97f839e KS |
104 | } |
105 | ||
ce1d6d7f KS |
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 | **/ | |
c32eb440 TG |
114 | _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) { |
115 | if (udev_enumerate) | |
313cefa1 | 116 | udev_enumerate->refcount++; |
c32eb440 | 117 | |
912541b0 | 118 | return udev_enumerate; |
bf7ad0ea KS |
119 | } |
120 | ||
ce1d6d7f KS |
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. | |
c1959569 | 127 | * |
725d7e6c | 128 | * Returns: #NULL |
ce1d6d7f | 129 | **/ |
c32eb440 TG |
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 | } | |
912541b0 | 136 | |
20bbd54f | 137 | return NULL; |
bf7ad0ea KS |
138 | } |
139 | ||
ce1d6d7f KS |
140 | /** |
141 | * udev_enumerate_get_udev: | |
142 | * @udev_enumerate: context | |
143 | * | |
21dbe43a KS |
144 | * Get the udev library context. |
145 | * | |
146 | * Returns: a pointer to the context. | |
ce1d6d7f | 147 | */ |
c32eb440 TG |
148 | _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) { |
149 | assert_return_errno(udev_enumerate, NULL, EINVAL); | |
3bf76824 | 150 | |
c32eb440 | 151 | return udev_enumerate->udev; |
3bf76824 LP |
152 | } |
153 | ||
a7c140c7 KS |
154 | /** |
155 | * udev_enumerate_get_list_entry: | |
156 | * @udev_enumerate: context | |
157 | * | |
21dbe43a KS |
158 | * Get the first entry of the sorted list of device paths. |
159 | * | |
160 | * Returns: a udev_list_entry. | |
a7c140c7 | 161 | */ |
c32eb440 | 162 | _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) { |
309f631d LP |
163 | struct udev_list_entry *e; |
164 | ||
c32eb440 TG |
165 | assert_return_errno(udev_enumerate, NULL, EINVAL); |
166 | ||
912541b0 | 167 | if (!udev_enumerate->devices_uptodate) { |
c32eb440 | 168 | sd_device *device; |
912541b0 KS |
169 | |
170 | udev_list_cleanup(&udev_enumerate->devices_list); | |
912541b0 | 171 | |
c32eb440 TG |
172 | FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) { |
173 | const char *syspath; | |
174 | int r; | |
912541b0 | 175 | |
c32eb440 TG |
176 | r = sd_device_get_syspath(device, &syspath); |
177 | if (r < 0) { | |
178 | errno = -r; | |
179 | return NULL; | |
912541b0 KS |
180 | } |
181 | ||
c32eb440 | 182 | udev_list_entry_add(&udev_enumerate->devices_list, syspath, NULL); |
912541b0 | 183 | } |
912541b0 KS |
184 | |
185 | udev_enumerate->devices_uptodate = true; | |
186 | } | |
c32eb440 | 187 | |
309f631d LP |
188 | e = udev_list_get_entry(&udev_enumerate->devices_list); |
189 | if (!e) | |
190 | errno = ENODATA; | |
191 | ||
192 | return e; | |
bf7ad0ea KS |
193 | } |
194 | ||
a7c140c7 KS |
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 | * | |
21dbe43a KS |
200 | * Match only devices belonging to a certain kernel subsystem. |
201 | * | |
a7c140c7 KS |
202 | * Returns: 0 on success, otherwise a negative error value. |
203 | */ | |
c32eb440 TG |
204 | _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) { |
205 | assert_return(udev_enumerate, -EINVAL); | |
206 | ||
54f0b4d9 TG |
207 | if (!subsystem) |
208 | return 0; | |
209 | ||
c32eb440 | 210 | return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, true); |
c97f839e KS |
211 | } |
212 | ||
a7c140c7 KS |
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 | * | |
21dbe43a KS |
218 | * Match only devices not belonging to a certain kernel subsystem. |
219 | * | |
a7c140c7 KS |
220 | * Returns: 0 on success, otherwise a negative error value. |
221 | */ | |
c32eb440 TG |
222 | _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) { |
223 | assert_return(udev_enumerate, -EINVAL); | |
224 | ||
54f0b4d9 TG |
225 | if (!subsystem) |
226 | return 0; | |
227 | ||
c32eb440 | 228 | return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, false); |
c97f839e KS |
229 | } |
230 | ||
a7c140c7 KS |
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 | * | |
21dbe43a KS |
237 | * Match only devices with a certain /sys device attribute. |
238 | * | |
a7c140c7 KS |
239 | * Returns: 0 on success, otherwise a negative error value. |
240 | */ | |
c32eb440 TG |
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 | ||
54f0b4d9 TG |
244 | if (!sysattr) |
245 | return 0; | |
246 | ||
c32eb440 | 247 | return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true); |
c97f839e KS |
248 | } |
249 | ||
a7c140c7 KS |
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 | * | |
21dbe43a KS |
256 | * Match only devices not having a certain /sys device attribute. |
257 | * | |
a7c140c7 KS |
258 | * Returns: 0 on success, otherwise a negative error value. |
259 | */ | |
c32eb440 TG |
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); | |
c97f839e | 262 | |
54f0b4d9 TG |
263 | if (!sysattr) |
264 | return 0; | |
265 | ||
c32eb440 | 266 | return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false); |
c97f839e KS |
267 | } |
268 | ||
a7c140c7 KS |
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 | * | |
21dbe43a KS |
275 | * Match only devices with a certain property. |
276 | * | |
a7c140c7 KS |
277 | * Returns: 0 on success, otherwise a negative error value. |
278 | */ | |
c32eb440 TG |
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 | ||
54f0b4d9 TG |
282 | if (!property) |
283 | return 0; | |
284 | ||
c32eb440 | 285 | return sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value); |
f0893502 KS |
286 | } |
287 | ||
28460195 KS |
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 | * | |
21dbe43a KS |
293 | * Match only devices with a certain tag. |
294 | * | |
28460195 KS |
295 | * Returns: 0 on success, otherwise a negative error value. |
296 | */ | |
c32eb440 TG |
297 | _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) { |
298 | assert_return(udev_enumerate, -EINVAL); | |
299 | ||
54f0b4d9 TG |
300 | if (!tag) |
301 | return 0; | |
302 | ||
c32eb440 | 303 | return sd_device_enumerator_add_match_tag(udev_enumerate->enumerator, tag); |
28460195 KS |
304 | } |
305 | ||
b05211fa KS |
306 | /** |
307 | * udev_enumerate_add_match_parent: | |
308 | * @udev_enumerate: context | |
a07e0114 | 309 | * @parent: parent device where to start searching |
b05211fa | 310 | * |
a07e0114 KS |
311 | * Return the devices on the subtree of one given device. The parent |
312 | * itself is included in the list. | |
b05211fa KS |
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 | */ | |
c32eb440 TG |
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) | |
912541b0 | 323 | return 0; |
c32eb440 TG |
324 | |
325 | return sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, parent->device); | |
b05211fa KS |
326 | } |
327 | ||
48a0170b KS |
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 | */ | |
c32eb440 TG |
346 | _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) { |
347 | assert_return(udev_enumerate, -EINVAL); | |
348 | ||
dee5e0b6 | 349 | return device_enumerator_add_match_is_initialized(udev_enumerate->enumerator); |
48a0170b KS |
350 | } |
351 | ||
cf5bd040 KS |
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 | * | |
21dbe43a KS |
357 | * Match only devices with a given /sys device name. |
358 | * | |
cf5bd040 KS |
359 | * Returns: 0 on success, otherwise a negative error value. |
360 | */ | |
c32eb440 TG |
361 | _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) { |
362 | assert_return(udev_enumerate, -EINVAL); | |
c97f839e | 363 | |
54f0b4d9 TG |
364 | if (!sysname) |
365 | return 0; | |
366 | ||
c32eb440 | 367 | return sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname); |
eb1f0e66 KS |
368 | } |
369 | ||
a7c140c7 KS |
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 | */ | |
c32eb440 | 379 | _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) { |
4afd3348 | 380 | _cleanup_(sd_device_unrefp) sd_device *device = NULL; |
c32eb440 | 381 | int r; |
b05211fa | 382 | |
c32eb440 | 383 | assert_return(udev_enumerate, -EINVAL); |
b05211fa | 384 | |
c32eb440 TG |
385 | if (!syspath) |
386 | return 0; | |
6ed03d1e | 387 | |
c32eb440 TG |
388 | r = sd_device_new_from_syspath(&device, syspath); |
389 | if (r < 0) | |
390 | return r; | |
6ed03d1e | 391 | |
19c9df44 | 392 | r = device_enumerator_add_device(udev_enumerate->enumerator, device); |
c32eb440 TG |
393 | if (r < 0) |
394 | return r; | |
b05211fa | 395 | |
912541b0 | 396 | return 0; |
eb1f0e66 | 397 | } |
bc8184ed | 398 | |
b05211fa KS |
399 | /** |
400 | * udev_enumerate_scan_devices: | |
401 | * @udev_enumerate: udev enumeration context | |
402 | * | |
21dbe43a KS |
403 | * Scan /sys for all devices which match the given filters. No matches |
404 | * will return all currently available devices. | |
405 | * | |
b05211fa KS |
406 | * Returns: 0 on success, otherwise a negative error value. |
407 | **/ | |
c32eb440 TG |
408 | _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) { |
409 | assert_return(udev_enumerate, -EINVAL); | |
b05211fa | 410 | |
c32eb440 | 411 | return device_enumerator_scan_devices(udev_enumerate->enumerator); |
b05211fa KS |
412 | } |
413 | ||
438d4c3c KS |
414 | /** |
415 | * udev_enumerate_scan_subsystems: | |
416 | * @udev_enumerate: udev enumeration context | |
417 | * | |
21dbe43a KS |
418 | * Scan /sys for all kernel subsystems, including buses, classes, drivers. |
419 | * | |
a7c140c7 | 420 | * Returns: 0 on success, otherwise a negative error value. |
438d4c3c | 421 | **/ |
c32eb440 TG |
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); | |
bc8184ed | 426 | } |