• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of systemd.
3 
4   Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10 
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <unistd.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 #include <sys/param.h>
31 #include <sys/sysmacros.h>
32 
33 #include "libudev.h"
34 #include "libudev-private.h"
35 
36 /**
37  * SECTION:libudev-enumerate
38  * @short_description: lookup and sort sys devices
39  *
40  * Lookup devices in the sys filesystem, filter devices by properties,
41  * and return a sorted list of devices.
42  */
43 
44 struct syspath {
45         char *syspath;
46         size_t len;
47 };
48 
49 /**
50  * udev_enumerate:
51  *
52  * Opaque object representing one device lookup/sort context.
53  */
54 struct udev_enumerate {
55         struct udev *udev;
56         int refcount;
57         struct udev_list sysattr_match_list;
58         struct udev_list sysattr_nomatch_list;
59         struct udev_list subsystem_match_list;
60         struct udev_list subsystem_nomatch_list;
61         struct udev_list sysname_match_list;
62         struct udev_list properties_match_list;
63         struct udev_list tags_match_list;
64         struct udev_device *parent_match;
65         struct udev_list devices_list;
66         struct syspath *devices;
67         unsigned int devices_cur;
68         unsigned int devices_max;
69         bool devices_uptodate:1;
70         bool match_is_initialized;
71 };
72 
73 /**
74  * udev_enumerate_new:
75  * @udev: udev library context
76  *
77  * Create an enumeration context to scan /sys.
78  *
79  * Returns: an enumeration context.
80  **/
udev_enumerate_new(struct udev * udev)81 _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
82 {
83         struct udev_enumerate *udev_enumerate;
84 
85         if (udev == NULL)
86                 return NULL;
87         udev_enumerate = new0(struct udev_enumerate, 1);
88         if (udev_enumerate == NULL)
89                 return NULL;
90         udev_enumerate->refcount = 1;
91         udev_enumerate->udev = udev;
92         udev_list_init(udev, &udev_enumerate->sysattr_match_list, false);
93         udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false);
94         udev_list_init(udev, &udev_enumerate->subsystem_match_list, true);
95         udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true);
96         udev_list_init(udev, &udev_enumerate->sysname_match_list, true);
97         udev_list_init(udev, &udev_enumerate->properties_match_list, false);
98         udev_list_init(udev, &udev_enumerate->tags_match_list, true);
99         udev_list_init(udev, &udev_enumerate->devices_list, false);
100         return udev_enumerate;
101 }
102 
103 /**
104  * udev_enumerate_ref:
105  * @udev_enumerate: context
106  *
107  * Take a reference of a enumeration context.
108  *
109  * Returns: the passed enumeration context
110  **/
udev_enumerate_ref(struct udev_enumerate * udev_enumerate)111 _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
112 {
113         if (udev_enumerate == NULL)
114                 return NULL;
115         udev_enumerate->refcount++;
116         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  **/
udev_enumerate_unref(struct udev_enumerate * udev_enumerate)128 _public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
129 {
130         unsigned int i;
131 
132         if (udev_enumerate == NULL)
133                 return NULL;
134         udev_enumerate->refcount--;
135         if (udev_enumerate->refcount > 0)
136                 return NULL;
137         udev_list_cleanup(&udev_enumerate->sysattr_match_list);
138         udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list);
139         udev_list_cleanup(&udev_enumerate->subsystem_match_list);
140         udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list);
141         udev_list_cleanup(&udev_enumerate->sysname_match_list);
142         udev_list_cleanup(&udev_enumerate->properties_match_list);
143         udev_list_cleanup(&udev_enumerate->tags_match_list);
144         udev_device_unref(udev_enumerate->parent_match);
145         udev_list_cleanup(&udev_enumerate->devices_list);
146         for (i = 0; i < udev_enumerate->devices_cur; i++)
147                 free(udev_enumerate->devices[i].syspath);
148         free(udev_enumerate->devices);
149         free(udev_enumerate);
150         return NULL;
151 }
152 
153 /**
154  * udev_enumerate_get_udev:
155  * @udev_enumerate: context
156  *
157  * Get the udev library context.
158  *
159  * Returns: a pointer to the context.
160  */
udev_enumerate_get_udev(struct udev_enumerate * udev_enumerate)161 _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
162 {
163         if (udev_enumerate == NULL)
164                 return NULL;
165         return udev_enumerate->udev;
166 }
167 
syspath_add(struct udev_enumerate * udev_enumerate,const char * syspath)168 static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
169 {
170         char *path;
171         struct syspath *entry;
172 
173         /* double array size if needed */
174         if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
175                 struct syspath *buf;
176                 unsigned int add;
177 
178                 add = udev_enumerate->devices_max;
179                 if (add < 1024)
180                         add = 1024;
181                 buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
182                 if (buf == NULL)
183                         return -ENOMEM;
184                 udev_enumerate->devices = buf;
185                 udev_enumerate->devices_max += add;
186         }
187 
188         path = strdup(syspath);
189         if (path == NULL)
190                 return -ENOMEM;
191         entry = &udev_enumerate->devices[udev_enumerate->devices_cur];
192         entry->syspath = path;
193         entry->len = strlen(path);
194         udev_enumerate->devices_cur++;
195         udev_enumerate->devices_uptodate = false;
196         return 0;
197 }
198 
syspath_cmp(const void * p1,const void * p2)199 static int syspath_cmp(const void *p1, const void *p2)
200 {
201         const struct syspath *path1 = p1;
202         const struct syspath *path2 = p2;
203         size_t len;
204         int ret;
205 
206         len = MIN(path1->len, path2->len);
207         ret = memcmp(path1->syspath, path2->syspath, len);
208         if (ret == 0) {
209                 if (path1->len < path2->len)
210                         ret = -1;
211                 else if (path1->len > path2->len)
212                         ret = 1;
213         }
214         return ret;
215 }
216 
217 /* For devices that should be moved to the absolute end of the list */
devices_delay_end(struct udev * udev,const char * syspath)218 static bool devices_delay_end(struct udev *udev, const char *syspath)
219 {
220         static const char *delay_device_list[] = {
221                 "/block/md",
222                 "/block/dm-",
223                 NULL
224         };
225         int i;
226 
227         for (i = 0; delay_device_list[i] != NULL; i++) {
228                 if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != NULL)
229                         return true;
230         }
231         return false;
232 }
233 
234 /* For devices that should just be moved a little bit later, just
235  * before the point where some common path prefix changes. Returns the
236  * number of characters that make up that common prefix */
devices_delay_later(struct udev * udev,const char * syspath)237 static size_t devices_delay_later(struct udev *udev, const char *syspath)
238 {
239         const char *c;
240 
241         /* For sound cards the control device must be enumerated last
242          * to make sure it's the final device node that gets ACLs
243          * applied. Applications rely on this fact and use ACL changes
244          * on the control node as an indicator that the ACL change of
245          * the entire sound card completed. The kernel makes this
246          * guarantee when creating those devices, and hence we should
247          * too when enumerating them. */
248 
249         if ((c = strstr(syspath, "/sound/card"))) {
250                 c += 11;
251                 c += strcspn(c, "/");
252 
253                 if (startswith(c, "/controlC"))
254                         return c - syspath + 1;
255         }
256 
257         return 0;
258 }
259 
260 /**
261  * udev_enumerate_get_list_entry:
262  * @udev_enumerate: context
263  *
264  * Get the first entry of the sorted list of device paths.
265  *
266  * Returns: a udev_list_entry.
267  */
udev_enumerate_get_list_entry(struct udev_enumerate * udev_enumerate)268 _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
269 {
270         if (udev_enumerate == NULL)
271                 return NULL;
272         if (!udev_enumerate->devices_uptodate) {
273                 unsigned int i;
274                 int move_later = -1;
275                 unsigned int max;
276                 struct syspath *prev = NULL;
277                 size_t move_later_prefix = 0;
278 
279                 udev_list_cleanup(&udev_enumerate->devices_list);
280                 qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
281 
282                 max = udev_enumerate->devices_cur;
283                 for (i = 0; i < max; i++) {
284                         struct syspath *entry = &udev_enumerate->devices[i];
285 
286                         /* skip duplicated entries */
287                         if (prev != NULL &&
288                             entry->len == prev->len &&
289                             memcmp(entry->syspath, prev->syspath, entry->len) == 0)
290                                 continue;
291                         prev = entry;
292 
293                         /* skip to be delayed devices, and add them to the end of the list */
294                         if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
295                                 syspath_add(udev_enumerate, entry->syspath);
296                                 /* need to update prev here for the case realloc() gives a different address */
297                                 prev = &udev_enumerate->devices[i];
298                                 continue;
299                         }
300 
301                         /* skip to be delayed devices, and move the to
302                          * the point where the prefix changes. We can
303                          * only move one item at a time. */
304                         if (move_later == -1) {
305                                 move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
306 
307                                 if (move_later_prefix > 0) {
308                                         move_later = i;
309                                         continue;
310                                 }
311                         }
312 
313                         if ((move_later >= 0) &&
314                              !strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) {
315 
316                                 udev_list_entry_add(&udev_enumerate->devices_list,
317                                                     udev_enumerate->devices[move_later].syspath, NULL);
318                                 move_later = -1;
319                         }
320 
321                         udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
322                 }
323 
324                 if (move_later >= 0)
325                         udev_list_entry_add(&udev_enumerate->devices_list,
326                                             udev_enumerate->devices[move_later].syspath, NULL);
327 
328                 /* add and cleanup delayed devices from end of list */
329                 for (i = max; i < udev_enumerate->devices_cur; i++) {
330                         struct syspath *entry = &udev_enumerate->devices[i];
331 
332                         udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
333                         free(entry->syspath);
334                 }
335                 udev_enumerate->devices_cur = max;
336 
337                 udev_enumerate->devices_uptodate = true;
338         }
339         return udev_list_get_entry(&udev_enumerate->devices_list);
340 }
341 
342 /**
343  * udev_enumerate_add_match_subsystem:
344  * @udev_enumerate: context
345  * @subsystem: filter for a subsystem of the device to include in the list
346  *
347  * Match only devices belonging to a certain kernel subsystem.
348  *
349  * Returns: 0 on success, otherwise a negative error value.
350  */
udev_enumerate_add_match_subsystem(struct udev_enumerate * udev_enumerate,const char * subsystem)351 _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
352 {
353         if (udev_enumerate == NULL)
354                 return -EINVAL;
355         if (subsystem == NULL)
356                 return 0;
357         if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL)
358                 return -ENOMEM;
359         return 0;
360 }
361 
362 /**
363  * udev_enumerate_add_nomatch_subsystem:
364  * @udev_enumerate: context
365  * @subsystem: filter for a subsystem of the device to exclude from the list
366  *
367  * Match only devices not belonging to a certain kernel subsystem.
368  *
369  * Returns: 0 on success, otherwise a negative error value.
370  */
udev_enumerate_add_nomatch_subsystem(struct udev_enumerate * udev_enumerate,const char * subsystem)371 _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
372 {
373         if (udev_enumerate == NULL)
374                 return -EINVAL;
375         if (subsystem == NULL)
376                 return 0;
377         if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL)
378                 return -ENOMEM;
379         return 0;
380 }
381 
382 /**
383  * udev_enumerate_add_match_sysattr:
384  * @udev_enumerate: context
385  * @sysattr: filter for a sys attribute at the device to include in the list
386  * @value: optional value of the sys attribute
387  *
388  * Match only devices with a certain /sys device attribute.
389  *
390  * Returns: 0 on success, otherwise a negative error value.
391  */
udev_enumerate_add_match_sysattr(struct udev_enumerate * udev_enumerate,const char * sysattr,const char * value)392 _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
393 {
394         if (udev_enumerate == NULL)
395                 return -EINVAL;
396         if (sysattr == NULL)
397                 return 0;
398         if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL)
399                 return -ENOMEM;
400         return 0;
401 }
402 
403 /**
404  * udev_enumerate_add_nomatch_sysattr:
405  * @udev_enumerate: context
406  * @sysattr: filter for a sys attribute at the device to exclude from the list
407  * @value: optional value of the sys attribute
408  *
409  * Match only devices not having a certain /sys device attribute.
410  *
411  * Returns: 0 on success, otherwise a negative error value.
412  */
udev_enumerate_add_nomatch_sysattr(struct udev_enumerate * udev_enumerate,const char * sysattr,const char * value)413 _public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
414 {
415         if (udev_enumerate == NULL)
416                 return -EINVAL;
417         if (sysattr == NULL)
418                 return 0;
419         if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL)
420                 return -ENOMEM;
421         return 0;
422 }
423 
match_sysattr_value(struct udev_device * dev,const char * sysattr,const char * match_val)424 static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
425 {
426         const char *val = NULL;
427         bool match = false;
428 
429         val = udev_device_get_sysattr_value(dev, sysattr);
430         if (val == NULL)
431                 goto exit;
432         if (match_val == NULL) {
433                 match = true;
434                 goto exit;
435         }
436         if (fnmatch(match_val, val, 0) == 0) {
437                 match = true;
438                 goto exit;
439         }
440 exit:
441         return match;
442 }
443 
444 /**
445  * udev_enumerate_add_match_property:
446  * @udev_enumerate: context
447  * @property: filter for a property of the device to include in the list
448  * @value: value of the property
449  *
450  * Match only devices with a certain property.
451  *
452  * Returns: 0 on success, otherwise a negative error value.
453  */
udev_enumerate_add_match_property(struct udev_enumerate * udev_enumerate,const char * property,const char * value)454 _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
455 {
456         if (udev_enumerate == NULL)
457                 return -EINVAL;
458         if (property == NULL)
459                 return 0;
460         if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL)
461                 return -ENOMEM;
462         return 0;
463 }
464 
465 /**
466  * udev_enumerate_add_match_tag:
467  * @udev_enumerate: context
468  * @tag: filter for a tag of the device to include in the list
469  *
470  * Match only devices with a certain tag.
471  *
472  * Returns: 0 on success, otherwise a negative error value.
473  */
udev_enumerate_add_match_tag(struct udev_enumerate * udev_enumerate,const char * tag)474 _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
475 {
476         if (udev_enumerate == NULL)
477                 return -EINVAL;
478         if (tag == NULL)
479                 return 0;
480         if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL)
481                 return -ENOMEM;
482         return 0;
483 }
484 
485 /**
486  * udev_enumerate_add_match_parent:
487  * @udev_enumerate: context
488  * @parent: parent device where to start searching
489  *
490  * Return the devices on the subtree of one given device. The parent
491  * itself is included in the list.
492  *
493  * A reference for the device is held until the udev_enumerate context
494  * is cleaned up.
495  *
496  * Returns: 0 on success, otherwise a negative error value.
497  */
udev_enumerate_add_match_parent(struct udev_enumerate * udev_enumerate,struct udev_device * parent)498 _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent)
499 {
500         if (udev_enumerate == NULL)
501                 return -EINVAL;
502         if (parent == NULL)
503                 return 0;
504         if (udev_enumerate->parent_match != NULL)
505                 udev_device_unref(udev_enumerate->parent_match);
506         udev_enumerate->parent_match = udev_device_ref(parent);
507         return 0;
508 }
509 
510 /**
511  * udev_enumerate_add_match_is_initialized:
512  * @udev_enumerate: context
513  *
514  * Match only devices which udev has set up already. This makes
515  * sure, that the device node permissions and context are properly set
516  * and that network devices are fully renamed.
517  *
518  * Usually, devices which are found in the kernel but not already
519  * handled by udev, have still pending events. Services should subscribe
520  * to monitor events and wait for these devices to become ready, instead
521  * of using uninitialized devices.
522  *
523  * For now, this will not affect devices which do not have a device node
524  * and are not network interfaces.
525  *
526  * Returns: 0 on success, otherwise a negative error value.
527  */
udev_enumerate_add_match_is_initialized(struct udev_enumerate * udev_enumerate)528 _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
529 {
530         if (udev_enumerate == NULL)
531                 return -EINVAL;
532         udev_enumerate->match_is_initialized = true;
533         return 0;
534 }
535 
536 /**
537  * udev_enumerate_add_match_sysname:
538  * @udev_enumerate: context
539  * @sysname: filter for the name of the device to include in the list
540  *
541  * Match only devices with a given /sys device name.
542  *
543  * Returns: 0 on success, otherwise a negative error value.
544  */
udev_enumerate_add_match_sysname(struct udev_enumerate * udev_enumerate,const char * sysname)545 _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
546 {
547         if (udev_enumerate == NULL)
548                 return -EINVAL;
549         if (sysname == NULL)
550                 return 0;
551         if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL)
552                 return -ENOMEM;
553         return 0;
554 }
555 
match_sysattr(struct udev_enumerate * udev_enumerate,struct udev_device * dev)556 static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
557 {
558         struct udev_list_entry *list_entry;
559 
560         /* skip list */
561         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
562                 if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
563                                         udev_list_entry_get_value(list_entry)))
564                         return false;
565         }
566         /* include list */
567         if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
568                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
569                         /* anything that does not match, will make it FALSE */
570                         if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
571                                                  udev_list_entry_get_value(list_entry)))
572                                 return false;
573                 }
574                 return true;
575         }
576         return true;
577 }
578 
match_property(struct udev_enumerate * udev_enumerate,struct udev_device * dev)579 static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
580 {
581         struct udev_list_entry *list_entry;
582         bool match = false;
583 
584         /* no match always matches */
585         if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
586                 return true;
587 
588         /* loop over matches */
589         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
590                 const char *match_key = udev_list_entry_get_name(list_entry);
591                 const char *match_value = udev_list_entry_get_value(list_entry);
592                 struct udev_list_entry *property_entry;
593 
594                 /* loop over device properties */
595                 udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
596                         const char *dev_key = udev_list_entry_get_name(property_entry);
597                         const char *dev_value = udev_list_entry_get_value(property_entry);
598 
599                         if (fnmatch(match_key, dev_key, 0) != 0)
600                                 continue;
601                         if (match_value == NULL && dev_value == NULL) {
602                                 match = true;
603                                 goto out;
604                         }
605                         if (match_value == NULL || dev_value == NULL)
606                                 continue;
607                         if (fnmatch(match_value, dev_value, 0) == 0) {
608                                 match = true;
609                                 goto out;
610                         }
611                 }
612         }
613 out:
614         return match;
615 }
616 
match_tag(struct udev_enumerate * udev_enumerate,struct udev_device * dev)617 static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
618 {
619         struct udev_list_entry *list_entry;
620 
621         /* no match always matches */
622         if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
623                 return true;
624 
625         /* loop over matches */
626         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
627                 if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
628                         return false;
629 
630         return true;
631 }
632 
match_parent(struct udev_enumerate * udev_enumerate,struct udev_device * dev)633 static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
634 {
635         if (udev_enumerate->parent_match == NULL)
636                 return true;
637 
638         return startswith(udev_device_get_devpath(dev), udev_device_get_devpath(udev_enumerate->parent_match));
639 }
640 
match_sysname(struct udev_enumerate * udev_enumerate,const char * sysname)641 static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
642 {
643         struct udev_list_entry *list_entry;
644 
645         if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
646                 return true;
647 
648         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
649                 if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
650                         continue;
651                 return true;
652         }
653         return false;
654 }
655 
scan_dir_and_add_devices(struct udev_enumerate * udev_enumerate,const char * basedir,const char * subdir1,const char * subdir2)656 static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
657                                     const char *basedir, const char *subdir1, const char *subdir2)
658 {
659         char path[UTIL_PATH_SIZE];
660         size_t l;
661         char *s;
662         DIR *dir;
663         struct dirent *dent;
664 
665         s = path;
666         l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL);
667         if (subdir1 != NULL)
668                 l = strpcpyl(&s, l, "/", subdir1, NULL);
669         if (subdir2 != NULL)
670                 strpcpyl(&s, l, "/", subdir2, NULL);
671         dir = opendir(path);
672         if (dir == NULL)
673                 return -ENOENT;
674         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
675                 char syspath[UTIL_PATH_SIZE];
676                 struct udev_device *dev;
677 
678                 if (dent->d_name[0] == '.')
679                         continue;
680 
681                 if (!match_sysname(udev_enumerate, dent->d_name))
682                         continue;
683 
684                 strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
685                 dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
686                 if (dev == NULL)
687                         continue;
688 
689                 if (udev_enumerate->match_is_initialized) {
690                         /*
691                          * All devices with a device node or network interfaces
692                          * possibly need udev to adjust the device node permission
693                          * or context, or rename the interface before it can be
694                          * reliably used from other processes.
695                          *
696                          * For now, we can only check these types of devices, we
697                          * might not store a database, and have no way to find out
698                          * for all other types of devices.
699                          */
700                         if (!udev_device_get_is_initialized(dev) &&
701                             (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
702                                 goto nomatch;
703                 }
704                 if (!match_parent(udev_enumerate, dev))
705                         goto nomatch;
706                 if (!match_tag(udev_enumerate, dev))
707                         goto nomatch;
708                 if (!match_property(udev_enumerate, dev))
709                         goto nomatch;
710                 if (!match_sysattr(udev_enumerate, dev))
711                         goto nomatch;
712 
713                 syspath_add(udev_enumerate, udev_device_get_syspath(dev));
714 nomatch:
715                 udev_device_unref(dev);
716         }
717         closedir(dir);
718         return 0;
719 }
720 
match_subsystem(struct udev_enumerate * udev_enumerate,const char * subsystem)721 static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
722 {
723         struct udev_list_entry *list_entry;
724 
725         if (!subsystem)
726                 return false;
727 
728         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
729                 if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
730                         return false;
731         }
732 
733         if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
734                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
735                         if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
736                                 return true;
737                 }
738                 return false;
739         }
740 
741         return true;
742 }
743 
scan_dir(struct udev_enumerate * udev_enumerate,const char * basedir,const char * subdir,const char * subsystem)744 static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
745 {
746         char path[UTIL_PATH_SIZE];
747         DIR *dir;
748         struct dirent *dent;
749 
750         strscpyl(path, sizeof(path), "/sys/", basedir, NULL);
751         dir = opendir(path);
752         if (dir == NULL)
753                 return -1;
754         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
755                 if (dent->d_name[0] == '.')
756                         continue;
757                 if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
758                         continue;
759                 scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
760         }
761         closedir(dir);
762         return 0;
763 }
764 
765 /**
766  * udev_enumerate_add_syspath:
767  * @udev_enumerate: context
768  * @syspath: path of a device
769  *
770  * Add a device to the list of devices, to retrieve it back sorted in dependency order.
771  *
772  * Returns: 0 on success, otherwise a negative error value.
773  */
udev_enumerate_add_syspath(struct udev_enumerate * udev_enumerate,const char * syspath)774 _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
775 {
776         struct udev_device *udev_device;
777 
778         if (udev_enumerate == NULL)
779                 return -EINVAL;
780         if (syspath == NULL)
781                 return 0;
782         /* resolve to real syspath */
783         udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
784         if (udev_device == NULL)
785                 return -EINVAL;
786         syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
787         udev_device_unref(udev_device);
788         return 0;
789 }
790 
scan_devices_tags(struct udev_enumerate * udev_enumerate)791 static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
792 {
793         struct udev_list_entry *list_entry;
794 
795         /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
796         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
797                 DIR *dir;
798                 struct dirent *dent;
799                 char path[UTIL_PATH_SIZE];
800 
801                 strscpyl(path, sizeof(path), UDEV_ROOT_RUN "/udev/tags/", udev_list_entry_get_name(list_entry), NULL);
802                 dir = opendir(path);
803                 if (dir == NULL)
804                         continue;
805                 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
806                         struct udev_device *dev;
807 
808                         if (dent->d_name[0] == '.')
809                                 continue;
810 
811                         dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name);
812                         if (dev == NULL)
813                                 continue;
814 
815                         if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev)))
816                                 goto nomatch;
817                         if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev)))
818                                 goto nomatch;
819                         if (!match_parent(udev_enumerate, dev))
820                                 goto nomatch;
821                         if (!match_property(udev_enumerate, dev))
822                                 goto nomatch;
823                         if (!match_sysattr(udev_enumerate, dev))
824                                 goto nomatch;
825 
826                         syspath_add(udev_enumerate, udev_device_get_syspath(dev));
827 nomatch:
828                         udev_device_unref(dev);
829                 }
830                 closedir(dir);
831         }
832         return 0;
833 }
834 
parent_add_child(struct udev_enumerate * enumerate,const char * path)835 static int parent_add_child(struct udev_enumerate *enumerate, const char *path)
836 {
837         struct udev_device *dev;
838         int r = 0;
839 
840         dev = udev_device_new_from_syspath(enumerate->udev, path);
841         if (dev == NULL)
842                 return -ENODEV;
843 
844         if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
845                 goto nomatch;
846         if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
847                 goto nomatch;
848         if (!match_property(enumerate, dev))
849                 goto nomatch;
850         if (!match_sysattr(enumerate, dev))
851                 goto nomatch;
852 
853         syspath_add(enumerate, udev_device_get_syspath(dev));
854         r = 1;
855 
856 nomatch:
857         udev_device_unref(dev);
858         return r;
859 }
860 
parent_crawl_children(struct udev_enumerate * enumerate,const char * path,int maxdepth)861 static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
862 {
863         DIR *d;
864         struct dirent *dent;
865 
866         d = opendir(path);
867         if (d == NULL)
868                 return -errno;
869 
870         for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
871                 char *child;
872 
873                 if (dent->d_name[0] == '.')
874                         continue;
875                 if (dent->d_type != DT_DIR)
876                         continue;
877                 if (asprintf(&child, "%s/%s", path, dent->d_name) < 0)
878                         continue;
879                 parent_add_child(enumerate, child);
880                 if (maxdepth > 0)
881                         parent_crawl_children(enumerate, child, maxdepth-1);
882                 free(child);
883         }
884 
885         closedir(d);
886         return 0;
887 }
888 
scan_devices_children(struct udev_enumerate * enumerate)889 static int scan_devices_children(struct udev_enumerate *enumerate)
890 {
891         const char *path;
892 
893         path = udev_device_get_syspath(enumerate->parent_match);
894         parent_add_child(enumerate, path);
895         return parent_crawl_children(enumerate, path, 256);
896 }
897 
scan_devices_all(struct udev_enumerate * udev_enumerate)898 static int scan_devices_all(struct udev_enumerate *udev_enumerate)
899 {
900         struct stat statbuf;
901 
902         if (stat("/sys/subsystem", &statbuf) == 0) {
903                 /* we have /subsystem/, forget all the old stuff */
904                 scan_dir(udev_enumerate, "subsystem", "devices", NULL);
905         } else {
906                 scan_dir(udev_enumerate, "bus", "devices", NULL);
907                 scan_dir(udev_enumerate, "class", NULL, NULL);
908         }
909         return 0;
910 }
911 
912 /**
913  * udev_enumerate_scan_devices:
914  * @udev_enumerate: udev enumeration context
915  *
916  * Scan /sys for all devices which match the given filters. No matches
917  * will return all currently available devices.
918  *
919  * Returns: 0 on success, otherwise a negative error value.
920  **/
udev_enumerate_scan_devices(struct udev_enumerate * udev_enumerate)921 _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
922 {
923         if (udev_enumerate == NULL)
924                 return -EINVAL;
925 
926         /* efficiently lookup tags only, we maintain a reverse-index */
927         if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
928                 return scan_devices_tags(udev_enumerate);
929 
930         /* walk the subtree of one parent device only */
931         if (udev_enumerate->parent_match != NULL)
932                 return scan_devices_children(udev_enumerate);
933 
934         /* scan devices of all subsystems */
935         return scan_devices_all(udev_enumerate);
936 }
937 
938 /**
939  * udev_enumerate_scan_subsystems:
940  * @udev_enumerate: udev enumeration context
941  *
942  * Scan /sys for all kernel subsystems, including buses, classes, drivers.
943  *
944  * Returns: 0 on success, otherwise a negative error value.
945  **/
udev_enumerate_scan_subsystems(struct udev_enumerate * udev_enumerate)946 _public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
947 {
948         struct stat statbuf;
949         const char *subsysdir;
950 
951         if (udev_enumerate == NULL)
952                 return -EINVAL;
953 
954         /* all kernel modules */
955         if (match_subsystem(udev_enumerate, "module"))
956                 scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
957 
958         if (stat("/sys/subsystem", &statbuf) == 0)
959                 subsysdir = "subsystem";
960         else
961                 subsysdir = "bus";
962 
963         /* all subsystems (only buses support coldplug) */
964         if (match_subsystem(udev_enumerate, "subsystem"))
965                 scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
966 
967         /* all subsystem drivers */
968         if (match_subsystem(udev_enumerate, "drivers"))
969                 scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
970         return 0;
971 }
972