LCOV - code coverage report
Current view: top level - libudev - libudev-enumerate.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 41 107 38.3 %
Date: 2015-07-29 18:47:03 Functions: 6 17 35.3 %

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

Generated by: LCOV version 1.11