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