LCOV - code coverage report
Current view: top level - libsystemd/sd-device - device-enumerator.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 338 557 60.7 %
Date: 2019-08-22 15:41:25 Functions: 30 41 73.2 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <fcntl.h>
       4             : #include <unistd.h>
       5             : 
       6             : #include "sd-device.h"
       7             : 
       8             : #include "alloc-util.h"
       9             : #include "device-enumerator-private.h"
      10             : #include "device-util.h"
      11             : #include "dirent-util.h"
      12             : #include "fd-util.h"
      13             : #include "set.h"
      14             : #include "sort-util.h"
      15             : #include "string-util.h"
      16             : #include "strv.h"
      17             : 
      18             : #define DEVICE_ENUMERATE_MAX_DEPTH 256
      19             : 
      20             : typedef enum DeviceEnumerationType {
      21             :         DEVICE_ENUMERATION_TYPE_DEVICES,
      22             :         DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
      23             :         _DEVICE_ENUMERATION_TYPE_MAX,
      24             :         _DEVICE_ENUMERATION_TYPE_INVALID = -1,
      25             : } DeviceEnumerationType;
      26             : 
      27             : struct sd_device_enumerator {
      28             :         unsigned n_ref;
      29             : 
      30             :         DeviceEnumerationType type;
      31             :         sd_device **devices;
      32             :         size_t n_devices, n_allocated, current_device_index;
      33             :         bool scan_uptodate;
      34             : 
      35             :         Set *match_subsystem;
      36             :         Set *nomatch_subsystem;
      37             :         Hashmap *match_sysattr;
      38             :         Hashmap *nomatch_sysattr;
      39             :         Hashmap *match_property;
      40             :         Set *match_sysname;
      41             :         Set *match_tag;
      42             :         Set *match_parent;
      43             :         bool match_allow_uninitialized;
      44             : };
      45             : 
      46          92 : _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
      47          92 :         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerator = NULL;
      48             : 
      49          92 :         assert(ret);
      50             : 
      51          92 :         enumerator = new(sd_device_enumerator, 1);
      52          92 :         if (!enumerator)
      53           0 :                 return -ENOMEM;
      54             : 
      55          92 :         *enumerator = (sd_device_enumerator) {
      56             :                 .n_ref = 1,
      57             :                 .type = _DEVICE_ENUMERATION_TYPE_INVALID,
      58             :         };
      59             : 
      60          92 :         *ret = TAKE_PTR(enumerator);
      61             : 
      62          92 :         return 0;
      63             : }
      64             : 
      65          92 : static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) {
      66             :         size_t i;
      67             : 
      68          92 :         assert(enumerator);
      69             : 
      70        5182 :         for (i = 0; i < enumerator->n_devices; i++)
      71        5090 :                 sd_device_unref(enumerator->devices[i]);
      72             : 
      73          92 :         free(enumerator->devices);
      74          92 :         set_free_free(enumerator->match_subsystem);
      75          92 :         set_free_free(enumerator->nomatch_subsystem);
      76          92 :         hashmap_free_free_free(enumerator->match_sysattr);
      77          92 :         hashmap_free_free_free(enumerator->nomatch_sysattr);
      78          92 :         hashmap_free_free_free(enumerator->match_property);
      79          92 :         set_free_free(enumerator->match_sysname);
      80          92 :         set_free_free(enumerator->match_tag);
      81          92 :         set_free_free(enumerator->match_parent);
      82             : 
      83          92 :         return mfree(enumerator);
      84             : }
      85             : 
      86          92 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_enumerator, sd_device_enumerator, device_enumerator_free);
      87             : 
      88          77 : _public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
      89             :         Set **set;
      90             :         int r;
      91             : 
      92          77 :         assert_return(enumerator, -EINVAL);
      93          77 :         assert_return(subsystem, -EINVAL);
      94             : 
      95          77 :         if (match)
      96          76 :                 set = &enumerator->match_subsystem;
      97             :         else
      98           1 :                 set = &enumerator->nomatch_subsystem;
      99             : 
     100          77 :         r = set_ensure_allocated(set, NULL);
     101          77 :         if (r < 0)
     102           0 :                 return r;
     103             : 
     104          77 :         r = set_put_strdup(*set, subsystem);
     105          77 :         if (r < 0)
     106           0 :                 return r;
     107             : 
     108          77 :         enumerator->scan_uptodate = false;
     109             : 
     110          77 :         return 0;
     111             : }
     112             : 
     113           0 : _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *_sysattr, const char *_value, int match) {
     114           0 :         _cleanup_free_ char *sysattr = NULL, *value = NULL;
     115             :         Hashmap **hashmap;
     116             :         int r;
     117             : 
     118           0 :         assert_return(enumerator, -EINVAL);
     119           0 :         assert_return(_sysattr, -EINVAL);
     120             : 
     121           0 :         if (match)
     122           0 :                 hashmap = &enumerator->match_sysattr;
     123             :         else
     124           0 :                 hashmap = &enumerator->nomatch_sysattr;
     125             : 
     126           0 :         r = hashmap_ensure_allocated(hashmap, NULL);
     127           0 :         if (r < 0)
     128           0 :                 return r;
     129             : 
     130           0 :         sysattr = strdup(_sysattr);
     131           0 :         if (!sysattr)
     132           0 :                 return -ENOMEM;
     133             : 
     134           0 :         if (_value) {
     135           0 :                 value = strdup(_value);
     136           0 :                 if (!value)
     137           0 :                         return -ENOMEM;
     138             :         }
     139             : 
     140           0 :         r = hashmap_put(*hashmap, sysattr, value);
     141           0 :         if (r < 0)
     142           0 :                 return r;
     143             : 
     144           0 :         sysattr = NULL;
     145           0 :         value = NULL;
     146             : 
     147           0 :         enumerator->scan_uptodate = false;
     148             : 
     149           0 :         return 0;
     150             : }
     151             : 
     152           1 : _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *_property, const char *_value) {
     153           1 :         _cleanup_free_ char *property = NULL, *value = NULL;
     154             :         int r;
     155             : 
     156           1 :         assert_return(enumerator, -EINVAL);
     157           1 :         assert_return(_property, -EINVAL);
     158             : 
     159           1 :         r = hashmap_ensure_allocated(&enumerator->match_property, NULL);
     160           1 :         if (r < 0)
     161           0 :                 return r;
     162             : 
     163           1 :         property = strdup(_property);
     164           1 :         if (!property)
     165           0 :                 return -ENOMEM;
     166             : 
     167           1 :         if (_value) {
     168           1 :                 value = strdup(_value);
     169           1 :                 if (!value)
     170           0 :                         return -ENOMEM;
     171             :         }
     172             : 
     173           1 :         r = hashmap_put(enumerator->match_property, property, value);
     174           1 :         if (r < 0)
     175           0 :                 return r;
     176             : 
     177           1 :         property = NULL;
     178           1 :         value = NULL;
     179             : 
     180           1 :         enumerator->scan_uptodate = false;
     181             : 
     182           1 :         return 0;
     183             : }
     184             : 
     185           0 : _public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
     186             :         int r;
     187             : 
     188           0 :         assert_return(enumerator, -EINVAL);
     189           0 :         assert_return(sysname, -EINVAL);
     190             : 
     191           0 :         r = set_ensure_allocated(&enumerator->match_sysname, NULL);
     192           0 :         if (r < 0)
     193           0 :                 return r;
     194             : 
     195           0 :         r = set_put_strdup(enumerator->match_sysname, sysname);
     196           0 :         if (r < 0)
     197           0 :                 return r;
     198             : 
     199           0 :         enumerator->scan_uptodate = false;
     200             : 
     201           0 :         return 0;
     202             : }
     203             : 
     204          11 : _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
     205             :         int r;
     206             : 
     207          11 :         assert_return(enumerator, -EINVAL);
     208          11 :         assert_return(tag, -EINVAL);
     209             : 
     210          11 :         r = set_ensure_allocated(&enumerator->match_tag, NULL);
     211          11 :         if (r < 0)
     212           0 :                 return r;
     213             : 
     214          11 :         r = set_put_strdup(enumerator->match_tag, tag);
     215          11 :         if (r < 0)
     216           0 :                 return r;
     217             : 
     218          11 :         enumerator->scan_uptodate = false;
     219             : 
     220          11 :         return 0;
     221             : }
     222             : 
     223           0 : static void device_enumerator_clear_match_parent(sd_device_enumerator *enumerator) {
     224           0 :         if (!enumerator)
     225           0 :                 return;
     226             : 
     227           0 :         set_clear_free(enumerator->match_parent);
     228             : }
     229             : 
     230           0 : int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent) {
     231             :         const char *path;
     232             :         int r;
     233             : 
     234           0 :         assert_return(enumerator, -EINVAL);
     235           0 :         assert_return(parent, -EINVAL);
     236             : 
     237           0 :         r = sd_device_get_syspath(parent, &path);
     238           0 :         if (r < 0)
     239           0 :                 return r;
     240             : 
     241           0 :         r = set_ensure_allocated(&enumerator->match_parent, NULL);
     242           0 :         if (r < 0)
     243           0 :                 return r;
     244             : 
     245           0 :         r = set_put_strdup(enumerator->match_parent, path);
     246           0 :         if (r < 0)
     247           0 :                 return r;
     248             : 
     249           0 :         enumerator->scan_uptodate = false;
     250             : 
     251           0 :         return 0;
     252             : }
     253             : 
     254           0 : _public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
     255           0 :         device_enumerator_clear_match_parent(enumerator);
     256           0 :         return device_enumerator_add_match_parent_incremental(enumerator, parent);
     257             : }
     258             : 
     259           9 : _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
     260           9 :         assert_return(enumerator, -EINVAL);
     261             : 
     262           9 :         enumerator->match_allow_uninitialized = true;
     263             : 
     264           9 :         enumerator->scan_uptodate = false;
     265             : 
     266           9 :         return 0;
     267             : }
     268             : 
     269           1 : int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
     270           1 :         assert_return(enumerator, -EINVAL);
     271             : 
     272           1 :         enumerator->match_allow_uninitialized = false;
     273             : 
     274           1 :         enumerator->scan_uptodate = false;
     275             : 
     276           1 :         return 0;
     277             : }
     278             : 
     279       34815 : static int device_compare(sd_device * const *_a, sd_device * const *_b) {
     280       34815 :         sd_device *a = *(sd_device **)_a, *b = *(sd_device **)_b;
     281             :         const char *devpath_a, *devpath_b, *sound_a;
     282             :         bool delay_a, delay_b;
     283             :         int r;
     284             : 
     285       34815 :         assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
     286       34815 :         assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
     287             : 
     288       34815 :         sound_a = strstr(devpath_a, "/sound/card");
     289       34815 :         if (sound_a) {
     290             :                 /* For sound cards the control device must be enumerated last to
     291             :                  * make sure it's the final device node that gets ACLs applied.
     292             :                  * Applications rely on this fact and use ACL changes on the
     293             :                  * control node as an indicator that the ACL change of the
     294             :                  * entire sound card completed. The kernel makes this guarantee
     295             :                  * when creating those devices, and hence we should too when
     296             :                  * enumerating them. */
     297         994 :                 sound_a += STRLEN("/sound/card");
     298         994 :                 sound_a = strchr(sound_a, '/');
     299             : 
     300         994 :                 if (sound_a) {
     301             :                         unsigned prefix_len;
     302             : 
     303         872 :                         prefix_len = sound_a - devpath_a;
     304             : 
     305         872 :                         if (strncmp(devpath_a, devpath_b, prefix_len) == 0) {
     306             :                                 const char *sound_b;
     307             : 
     308         395 :                                 sound_b = devpath_b + prefix_len;
     309             : 
     310         420 :                                 if (startswith(sound_a, "/controlC") &&
     311          25 :                                     !startswith(sound_b, "/contolC"))
     312          25 :                                         return 1;
     313             : 
     314         740 :                                 if (!startswith(sound_a, "/controlC") &&
     315         370 :                                     startswith(sound_b, "/controlC"))
     316          13 :                                         return -1;
     317             :                         }
     318             :                 }
     319             :         }
     320             : 
     321             :         /* md and dm devices are enumerated after all other devices */
     322       34777 :         delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-");
     323       34777 :         delay_b = strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-");
     324       34777 :         r = CMP(delay_a, delay_b);
     325       34777 :         if (r != 0)
     326         282 :                 return r;
     327             : 
     328       34495 :         return strcmp(devpath_a, devpath_b);
     329             : }
     330             : 
     331        5138 : int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
     332        5138 :         assert_return(enumerator, -EINVAL);
     333        5138 :         assert_return(device, -EINVAL);
     334             : 
     335        5138 :         if (!GREEDY_REALLOC(enumerator->devices, enumerator->n_allocated, enumerator->n_devices + 1))
     336           0 :                 return -ENOMEM;
     337             : 
     338        5138 :         enumerator->devices[enumerator->n_devices++] = sd_device_ref(device);
     339             : 
     340        5138 :         return 0;
     341             : }
     342             : 
     343           0 : static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
     344             :         const char *value;
     345             :         int r;
     346             : 
     347           0 :         assert(device);
     348           0 :         assert(sysattr);
     349             : 
     350           0 :         r = sd_device_get_sysattr_value(device, sysattr, &value);
     351           0 :         if (r < 0)
     352           0 :                 return false;
     353             : 
     354           0 :         if (!match_value)
     355           0 :                 return true;
     356             : 
     357           0 :         if (fnmatch(match_value, value, 0) == 0)
     358           0 :                 return true;
     359             : 
     360           0 :         return false;
     361             : }
     362             : 
     363        5129 : static bool match_sysattr(sd_device_enumerator *enumerator, sd_device *device) {
     364             :         const char *sysattr;
     365             :         const char *value;
     366             :         Iterator i;
     367             : 
     368        5129 :         assert(enumerator);
     369        5129 :         assert(device);
     370             : 
     371        5129 :         HASHMAP_FOREACH_KEY(value, sysattr, enumerator->nomatch_sysattr, i)
     372           0 :                 if (match_sysattr_value(device, sysattr, value))
     373           0 :                         return false;
     374             : 
     375        5129 :         HASHMAP_FOREACH_KEY(value, sysattr, enumerator->match_sysattr, i)
     376           0 :                 if (!match_sysattr_value(device, sysattr, value))
     377           0 :                         return false;
     378             : 
     379        5129 :         return true;
     380             : }
     381             : 
     382        5868 : static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
     383             :         const char *property;
     384             :         const char *value;
     385             :         Iterator i;
     386             : 
     387        5868 :         assert(enumerator);
     388        5868 :         assert(device);
     389             : 
     390        5868 :         if (hashmap_isempty(enumerator->match_property))
     391        5126 :                 return true;
     392             : 
     393        1481 :         HASHMAP_FOREACH_KEY(value, property, enumerator->match_property, i) {
     394             :                 const char *property_dev, *value_dev;
     395             : 
     396        5372 :                 FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
     397        4633 :                         if (fnmatch(property, property_dev, 0) != 0)
     398        4603 :                                 continue;
     399             : 
     400          30 :                         if (!value && !value_dev)
     401           3 :                                 return true;
     402             : 
     403          30 :                         if (!value || !value_dev)
     404           0 :                                 continue;
     405             : 
     406          30 :                         if (fnmatch(value, value_dev, 0) == 0)
     407           3 :                                 return true;
     408             :                 }
     409             :         }
     410             : 
     411         739 :         return false;
     412             : }
     413             : 
     414        5263 : static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
     415             :         const char *tag;
     416             :         Iterator i;
     417             : 
     418        5263 :         assert(enumerator);
     419        5263 :         assert(device);
     420             : 
     421        5263 :         SET_FOREACH(tag, enumerator->match_tag, i)
     422           0 :                 if (!sd_device_has_tag(device, tag))
     423           0 :                         return false;
     424             : 
     425        5263 :         return true;
     426             : }
     427             : 
     428        5868 : static bool match_parent(sd_device_enumerator *enumerator, sd_device *device) {
     429             :         const char *syspath_parent, *syspath;
     430             :         Iterator i;
     431             : 
     432        5868 :         assert(enumerator);
     433        5868 :         assert(device);
     434             : 
     435        5868 :         if (set_isempty(enumerator->match_parent))
     436        5868 :                 return true;
     437             : 
     438           0 :         assert_se(sd_device_get_syspath(device, &syspath) >= 0);
     439             : 
     440           0 :         SET_FOREACH(syspath_parent, enumerator->match_parent, i)
     441           0 :                 if (path_startswith(syspath, syspath_parent))
     442           0 :                         return true;
     443             : 
     444           0 :         return false;
     445             : }
     446             : 
     447        5879 : static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
     448             :         const char *sysname_match;
     449             :         Iterator i;
     450             : 
     451        5879 :         assert(enumerator);
     452        5879 :         assert(sysname);
     453             : 
     454        5879 :         if (set_isempty(enumerator->match_sysname))
     455        5879 :                 return true;
     456             : 
     457           0 :         SET_FOREACH(sysname_match, enumerator->match_sysname, i)
     458           0 :                 if (fnmatch(sysname_match, sysname, 0) == 0)
     459           0 :                         return true;
     460             : 
     461           0 :         return false;
     462             : }
     463             : 
     464         690 : static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
     465         690 :         _cleanup_closedir_ DIR *dir = NULL;
     466             :         char *path;
     467             :         struct dirent *dent;
     468         690 :         int r = 0;
     469             : 
     470         690 :         assert(enumerator);
     471         690 :         assert(basedir);
     472             : 
     473        4830 :         path = strjoina("/sys/", basedir, "/");
     474             : 
     475         690 :         if (subdir1)
     476        4802 :                 path = strjoina(path, subdir1, "/");
     477             : 
     478         690 :         if (subdir2)
     479        2240 :                 path = strjoina(path, subdir2, "/");
     480             : 
     481         690 :         dir = opendir(path);
     482         690 :         if (!dir)
     483           0 :                 return -errno;
     484             : 
     485        7344 :         FOREACH_DIRENT_ALL(dent, dir, return -errno) {
     486        6654 :                 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
     487        6654 :                 char syspath[strlen(path) + 1 + strlen(dent->d_name) + 1];
     488             :                 int initialized, k;
     489             : 
     490        6654 :                 if (dent->d_name[0] == '.')
     491        1380 :                         continue;
     492             : 
     493        5274 :                 if (!match_sysname(enumerator, dent->d_name))
     494           0 :                         continue;
     495             : 
     496        5274 :                 (void) sprintf(syspath, "%s%s", path, dent->d_name);
     497             : 
     498        5274 :                 k = sd_device_new_from_syspath(&device, syspath);
     499        5274 :                 if (k < 0) {
     500          11 :                         if (k != -ENODEV)
     501             :                                 /* this is necessarily racey, so ignore missing devices */
     502           0 :                                 r = k;
     503             : 
     504          11 :                         continue;
     505             :                 }
     506             : 
     507        5263 :                 initialized = sd_device_get_is_initialized(device);
     508        5263 :                 if (initialized < 0) {
     509           0 :                         r = initialized;
     510           0 :                         continue;
     511             :                 }
     512             : 
     513             :                 /*
     514             :                  * All devices with a device node or network interfaces
     515             :                  * possibly need udev to adjust the device node permission
     516             :                  * or context, or rename the interface before it can be
     517             :                  * reliably used from other processes.
     518             :                  *
     519             :                  * For now, we can only check these types of devices, we
     520             :                  * might not store a database, and have no way to find out
     521             :                  * for all other types of devices.
     522             :                  */
     523        5263 :                 if (!enumerator->match_allow_uninitialized &&
     524         730 :                     !initialized &&
     525        1460 :                     (sd_device_get_devnum(device, NULL) >= 0 ||
     526         730 :                      sd_device_get_ifindex(device, NULL) >= 0))
     527           0 :                         continue;
     528             : 
     529        5263 :                 if (!match_parent(enumerator, device))
     530           0 :                         continue;
     531             : 
     532        5263 :                 if (!match_tag(enumerator, device))
     533           0 :                         continue;
     534             : 
     535        5263 :                 if (!match_property(enumerator, device))
     536         739 :                         continue;
     537             : 
     538        4524 :                 if (!match_sysattr(enumerator, device))
     539           0 :                         continue;
     540             : 
     541        4524 :                 k = device_enumerator_add_device(enumerator, device);
     542        4524 :                 if (k < 0)
     543           0 :                         r = k;
     544             :         }
     545             : 
     546         690 :         return r;
     547             : }
     548             : 
     549        8990 : static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
     550             :         const char *subsystem_match;
     551             :         Iterator i;
     552             : 
     553        8990 :         assert(enumerator);
     554             : 
     555        8990 :         if (!subsystem)
     556           0 :                 return false;
     557             : 
     558        9094 :         SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem, i)
     559         105 :                 if (fnmatch(subsystem_match, subsystem, 0) == 0)
     560           1 :                         return false;
     561             : 
     562        8989 :         if (set_isempty(enumerator->match_subsystem))
     563        1219 :                 return true;
     564             : 
     565       15669 :         SET_FOREACH(subsystem_match, enumerator->match_subsystem, i)
     566        7977 :                 if (fnmatch(subsystem_match, subsystem, 0) == 0)
     567          78 :                         return true;
     568             : 
     569        7692 :         return false;
     570             : }
     571             : 
     572         160 : static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
     573         160 :         _cleanup_closedir_ DIR *dir = NULL;
     574             :         char *path;
     575             :         struct dirent *dent;
     576         160 :         int r = 0;
     577             : 
     578         800 :         path = strjoina("/sys/", basedir);
     579             : 
     580         160 :         dir = opendir(path);
     581         160 :         if (!dir)
     582           0 :                 return -errno;
     583             : 
     584         160 :         log_debug("sd-device-enumerator: Scanning %s", path);
     585             : 
     586        8859 :         FOREACH_DIRENT_ALL(dent, dir, return -errno) {
     587             :                 int k;
     588             : 
     589        8699 :                 if (dent->d_name[0] == '.')
     590         320 :                         continue;
     591             : 
     592        8379 :                 if (!match_subsystem(enumerator, subsystem ? : dent->d_name))
     593        7693 :                         continue;
     594             : 
     595         686 :                 k = enumerator_scan_dir_and_add_devices(enumerator, basedir, dent->d_name, subdir);
     596         686 :                 if (k < 0)
     597           0 :                         r = k;
     598             :         }
     599             : 
     600         160 :         return r;
     601             : }
     602             : 
     603          11 : static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
     604          11 :         _cleanup_closedir_ DIR *dir = NULL;
     605             :         char *path;
     606             :         struct dirent *dent;
     607          11 :         int r = 0;
     608             : 
     609          11 :         assert(enumerator);
     610          11 :         assert(tag);
     611             : 
     612          55 :         path = strjoina("/run/udev/tags/", tag);
     613             : 
     614          11 :         dir = opendir(path);
     615          11 :         if (!dir) {
     616           0 :                 if (errno != ENOENT)
     617           0 :                         return log_debug_errno(errno, "sd-device-enumerator: Failed to open tags directory %s: %m", path);
     618           0 :                 return 0;
     619             :         }
     620             : 
     621             :         /* TODO: filter away subsystems? */
     622             : 
     623         638 :         FOREACH_DIRENT_ALL(dent, dir, return -errno) {
     624         627 :                 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
     625             :                 const char *subsystem, *sysname;
     626             :                 int k;
     627             : 
     628         627 :                 if (dent->d_name[0] == '.')
     629          22 :                         continue;
     630             : 
     631         605 :                 k = sd_device_new_from_device_id(&device, dent->d_name);
     632         605 :                 if (k < 0) {
     633           0 :                         if (k != -ENODEV)
     634             :                                 /* this is necessarily racy, so ignore missing devices */
     635           0 :                                 r = k;
     636             : 
     637           0 :                         continue;
     638             :                 }
     639             : 
     640         605 :                 k = sd_device_get_subsystem(device, &subsystem);
     641         605 :                 if (k < 0) {
     642           0 :                         r = k;
     643           0 :                         continue;
     644             :                 }
     645             : 
     646         605 :                 if (!match_subsystem(enumerator, subsystem))
     647           0 :                         continue;
     648             : 
     649         605 :                 k = sd_device_get_sysname(device, &sysname);
     650         605 :                 if (k < 0) {
     651           0 :                         r = k;
     652           0 :                         continue;
     653             :                 }
     654             : 
     655         605 :                 if (!match_sysname(enumerator, sysname))
     656           0 :                         continue;
     657             : 
     658         605 :                 if (!match_parent(enumerator, device))
     659           0 :                         continue;
     660             : 
     661         605 :                 if (!match_property(enumerator, device))
     662           0 :                         continue;
     663             : 
     664         605 :                 if (!match_sysattr(enumerator, device))
     665           0 :                         continue;
     666             : 
     667         605 :                 k = device_enumerator_add_device(enumerator, device);
     668         605 :                 if (k < 0) {
     669           0 :                         r = k;
     670           0 :                         continue;
     671             :                 }
     672             :         }
     673             : 
     674          11 :         return r;
     675             : }
     676             : 
     677          11 : static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
     678             :         const char *tag;
     679             :         Iterator i;
     680          11 :         int r = 0;
     681             : 
     682          11 :         assert(enumerator);
     683             : 
     684          22 :         SET_FOREACH(tag, enumerator->match_tag, i) {
     685             :                 int k;
     686             : 
     687          11 :                 k = enumerator_scan_devices_tag(enumerator, tag);
     688          11 :                 if (k < 0)
     689           0 :                         r = k;
     690             :         }
     691             : 
     692          11 :         return r;
     693             : }
     694             : 
     695           0 : static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
     696           0 :         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
     697             :         const char *subsystem, *sysname;
     698             :         int r;
     699             : 
     700           0 :         r = sd_device_new_from_syspath(&device, path);
     701           0 :         if (r == -ENODEV)
     702             :                 /* this is necessarily racy, so ignore missing devices */
     703           0 :                 return 0;
     704           0 :         else if (r < 0)
     705           0 :                 return r;
     706             : 
     707           0 :         r = sd_device_get_subsystem(device, &subsystem);
     708           0 :         if (r == -ENOENT)
     709           0 :                 return 0;
     710           0 :         if (r < 0)
     711           0 :                 return r;
     712             : 
     713           0 :         if (!match_subsystem(enumerator, subsystem))
     714           0 :                 return 0;
     715             : 
     716           0 :         r = sd_device_get_sysname(device, &sysname);
     717           0 :         if (r < 0)
     718           0 :                 return r;
     719             : 
     720           0 :         if (!match_sysname(enumerator, sysname))
     721           0 :                 return 0;
     722             : 
     723           0 :         if (!match_property(enumerator, device))
     724           0 :                 return 0;
     725             : 
     726           0 :         if (!match_sysattr(enumerator, device))
     727           0 :                 return 0;
     728             : 
     729           0 :         r = device_enumerator_add_device(enumerator, device);
     730           0 :         if (r < 0)
     731           0 :                 return r;
     732             : 
     733           0 :         return 1;
     734             : }
     735             : 
     736           0 : static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
     737           0 :         _cleanup_closedir_ DIR *dir = NULL;
     738             :         struct dirent *dent;
     739           0 :         int r = 0;
     740             : 
     741           0 :         dir = opendir(path);
     742           0 :         if (!dir)
     743           0 :                 return log_debug_errno(errno, "sd-device-enumerator: Failed to open parent directory %s: %m", path);
     744             : 
     745           0 :         FOREACH_DIRENT_ALL(dent, dir, return -errno) {
     746           0 :                 _cleanup_free_ char *child = NULL;
     747             :                 int k;
     748             : 
     749           0 :                 if (dent->d_name[0] == '.')
     750           0 :                         continue;
     751             : 
     752           0 :                 if (dent->d_type != DT_DIR)
     753           0 :                         continue;
     754             : 
     755           0 :                 child = path_join(path, dent->d_name);
     756           0 :                 if (!child)
     757           0 :                         return -ENOMEM;
     758             : 
     759           0 :                 k = parent_add_child(enumerator, child);
     760           0 :                 if (k < 0)
     761           0 :                         r = k;
     762             : 
     763           0 :                 if (maxdepth > 0)
     764           0 :                         parent_crawl_children(enumerator, child, maxdepth - 1);
     765             :                 else
     766           0 :                         log_debug("sd-device-enumerator: Max depth reached, %s: ignoring devices", child);
     767             :         }
     768             : 
     769           0 :         return r;
     770             : }
     771             : 
     772           0 : static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
     773             :         const char *path;
     774           0 :         int r = 0, k;
     775             :         Iterator i;
     776             : 
     777           0 :         SET_FOREACH(path, enumerator->match_parent, i) {
     778           0 :                 k = parent_add_child(enumerator, path);
     779           0 :                 if (k < 0)
     780           0 :                         r = k;
     781             : 
     782           0 :                 k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
     783           0 :                 if (k < 0)
     784           0 :                         r = k;
     785             :         }
     786             : 
     787           0 :         return r;
     788             : }
     789             : 
     790          79 : static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
     791          79 :         int r = 0;
     792             : 
     793          79 :         log_debug("sd-device-enumerator: Scan all dirs");
     794             : 
     795          79 :         if (access("/sys/subsystem", F_OK) >= 0) {
     796             :                 /* we have /subsystem/, forget all the old stuff */
     797           0 :                 r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
     798           0 :                 if (r < 0)
     799           0 :                         return log_debug_errno(r, "sd-device-enumerator: Failed to scan /sys/subsystem: %m");
     800             :         } else {
     801             :                 int k;
     802             : 
     803          79 :                 k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
     804          79 :                 if (k < 0) {
     805           0 :                         log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
     806           0 :                         r = k;
     807             :                 }
     808             : 
     809          79 :                 k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
     810          79 :                 if (k < 0) {
     811           0 :                         log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
     812           0 :                         r = k;
     813             :                 }
     814             :         }
     815             : 
     816          79 :         return r;
     817             : }
     818             : 
     819          92 : static void device_enumerator_dedup_devices(sd_device_enumerator *enumerator) {
     820             :         sd_device **a, **b, **end;
     821             : 
     822          92 :         assert(enumerator);
     823             : 
     824          92 :         if (enumerator->n_devices <= 1)
     825          20 :                 return;
     826             : 
     827          72 :         a = enumerator->devices + 1;
     828          72 :         b = enumerator->devices;
     829          72 :         end = enumerator->devices + enumerator->n_devices;
     830             : 
     831        5109 :         for (; a < end; a++) {
     832             :                 const char *devpath_a, *devpath_b;
     833             : 
     834        5037 :                 assert_se(sd_device_get_devpath(*a, &devpath_a) >= 0);
     835        5037 :                 assert_se(sd_device_get_devpath(*b, &devpath_b) >= 0);
     836             : 
     837        5037 :                 if (path_equal(devpath_a, devpath_b))
     838          48 :                         sd_device_unref(*a);
     839             :                 else
     840        4989 :                         *(++b) = *a;
     841             :         }
     842             : 
     843          72 :         enumerator->n_devices = b - enumerator->devices + 1;
     844             : }
     845             : 
     846          92 : int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
     847          92 :         int r = 0, k;
     848             :         size_t i;
     849             : 
     850          92 :         assert(enumerator);
     851             : 
     852          92 :         if (enumerator->scan_uptodate &&
     853           2 :             enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
     854           2 :                 return 0;
     855             : 
     856          90 :         for (i = 0; i < enumerator->n_devices; i++)
     857           0 :                 sd_device_unref(enumerator->devices[i]);
     858             : 
     859          90 :         enumerator->n_devices = 0;
     860             : 
     861          90 :         if (!set_isempty(enumerator->match_tag)) {
     862          11 :                 k = enumerator_scan_devices_tags(enumerator);
     863          11 :                 if (k < 0)
     864           0 :                         r = k;
     865          79 :         } else if (enumerator->match_parent) {
     866           0 :                 k = enumerator_scan_devices_children(enumerator);
     867           0 :                 if (k < 0)
     868           0 :                         r = k;
     869             :         } else {
     870          79 :                 k = enumerator_scan_devices_all(enumerator);
     871          79 :                 if (k < 0)
     872           0 :                         r = k;
     873             :         }
     874             : 
     875          90 :         typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
     876          90 :         device_enumerator_dedup_devices(enumerator);
     877             : 
     878          90 :         enumerator->scan_uptodate = true;
     879          90 :         enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
     880             : 
     881          90 :         return r;
     882             : }
     883             : 
     884          84 : _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
     885             :         int r;
     886             : 
     887          84 :         assert_return(enumerator, NULL);
     888             : 
     889          84 :         r = device_enumerator_scan_devices(enumerator);
     890          84 :         if (r < 0)
     891           0 :                 return NULL;
     892             : 
     893          84 :         enumerator->current_device_index = 0;
     894             : 
     895          84 :         if (enumerator->n_devices == 0)
     896           0 :                 return NULL;
     897             : 
     898          84 :         return enumerator->devices[0];
     899             : }
     900             : 
     901        2795 : _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
     902        2795 :         assert_return(enumerator, NULL);
     903             : 
     904        2795 :         if (!enumerator->scan_uptodate ||
     905        2795 :             enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
     906        2795 :             enumerator->current_device_index + 1 >= enumerator->n_devices)
     907          84 :                 return NULL;
     908             : 
     909        2711 :         return enumerator->devices[++enumerator->current_device_index];
     910             : }
     911             : 
     912           2 : int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
     913             :         const char *subsysdir;
     914           2 :         int r = 0, k;
     915             :         size_t i;
     916             : 
     917           2 :         assert(enumerator);
     918             : 
     919           2 :         if (enumerator->scan_uptodate &&
     920           0 :             enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
     921           0 :                 return 0;
     922             : 
     923           2 :         for (i = 0; i < enumerator->n_devices; i++)
     924           0 :                 sd_device_unref(enumerator->devices[i]);
     925             : 
     926           2 :         enumerator->n_devices = 0;
     927             : 
     928             :         /* modules */
     929           2 :         if (match_subsystem(enumerator, "module")) {
     930           2 :                 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
     931           2 :                 if (k < 0) {
     932           0 :                         log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
     933           0 :                         r = k;
     934             :                 }
     935             :         }
     936             : 
     937           2 :         if (access("/sys/subsystem", F_OK) >= 0)
     938           0 :                 subsysdir = "subsystem";
     939             :         else
     940           2 :                 subsysdir = "bus";
     941             : 
     942             :         /* subsystems (only buses support coldplug) */
     943           2 :         if (match_subsystem(enumerator, "subsystem")) {
     944           2 :                 k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL);
     945           2 :                 if (k < 0) {
     946           0 :                         log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
     947           0 :                         r = k;
     948             :                 }
     949             :         }
     950             : 
     951             :         /* subsystem drivers */
     952           2 :         if (match_subsystem(enumerator, "drivers")) {
     953           2 :                 k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers");
     954           2 :                 if (k < 0) {
     955           0 :                         log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
     956           0 :                         r = k;
     957             :                 }
     958             :         }
     959             : 
     960           2 :         typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
     961           2 :         device_enumerator_dedup_devices(enumerator);
     962             : 
     963           2 :         enumerator->scan_uptodate = true;
     964           2 :         enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
     965             : 
     966           2 :         return r;
     967             : }
     968             : 
     969           1 : _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
     970             :         int r;
     971             : 
     972           1 :         assert_return(enumerator, NULL);
     973             : 
     974           1 :         r = device_enumerator_scan_subsystems(enumerator);
     975           1 :         if (r < 0)
     976           0 :                 return NULL;
     977             : 
     978           1 :         enumerator->current_device_index = 0;
     979             : 
     980           1 :         if (enumerator->n_devices == 0)
     981           0 :                 return NULL;
     982             : 
     983           1 :         return enumerator->devices[0];
     984             : }
     985             : 
     986         386 : _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
     987         386 :         assert_return(enumerator, NULL);
     988             : 
     989         386 :         if (!enumerator->scan_uptodate ||
     990         386 :             enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
     991         386 :             enumerator->current_device_index + 1 >= enumerator->n_devices)
     992           1 :                 return NULL;
     993             : 
     994         385 :         return enumerator->devices[++enumerator->current_device_index];
     995             : }
     996             : 
     997           7 : sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
     998           7 :         assert_return(enumerator, NULL);
     999             : 
    1000           7 :         if (!enumerator->scan_uptodate)
    1001           0 :                 return NULL;
    1002             : 
    1003           7 :         enumerator->current_device_index = 0;
    1004             : 
    1005           7 :         if (enumerator->n_devices == 0)
    1006           0 :                 return NULL;
    1007             : 
    1008           7 :         return enumerator->devices[0];
    1009             : }
    1010             : 
    1011        1909 : sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
    1012        1909 :         assert_return(enumerator, NULL);
    1013             : 
    1014        1909 :         if (!enumerator->scan_uptodate ||
    1015        1909 :             enumerator->current_device_index + 1 >= enumerator->n_devices)
    1016           7 :                 return NULL;
    1017             : 
    1018        1902 :         return enumerator->devices[++enumerator->current_device_index];
    1019             : }
    1020             : 
    1021           0 : sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices) {
    1022           0 :         assert(enumerator);
    1023           0 :         assert(ret_n_devices);
    1024             : 
    1025           0 :         if (!enumerator->scan_uptodate)
    1026           0 :                 return NULL;
    1027             : 
    1028           0 :         *ret_n_devices = enumerator->n_devices;
    1029           0 :         return enumerator->devices;
    1030             : }

Generated by: LCOV version 1.14