LCOV - code coverage report
Current view: top level - libsystemd/sd-device - device-enumerator.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 141 524 26.9 %
Date: 2015-07-29 18:47:03 Functions: 17 36 47.2 %

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

Generated by: LCOV version 1.11