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