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