device-enumerator.c revision 3ffd4af22052963e7a29431721ee204e634bea75
/***
This file is part of systemd.
Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
Copyright 2014-2015 Tom Gundersen <teg@jklm.no>
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-device.h"
#include "device-enumerator-private.h"
#include "device-util.h"
#include "fd-util.h"
#include "prioq.h"
#include "set.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
#define DEVICE_ENUMERATE_MAX_DEPTH 256
typedef enum DeviceEnumerationType {
struct sd_device_enumerator {
unsigned n_ref;
bool scan_uptodate;
};
if (!enumerator)
return -ENOMEM;
*ret = enumerator;
enumerator = NULL;
return 0;
}
return enumerator;
}
}
return NULL;
}
_public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
int r;
if (match)
else
if (r < 0)
return r;
if (r < 0)
return r;
enumerator->scan_uptodate = false;
return 0;
}
_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *_sysattr, const char *_value, int match) {
int r;
if (match)
else
if (r < 0)
return r;
if (!sysattr)
return -ENOMEM;
if (_value) {
if (!value)
return -ENOMEM;
}
if (r < 0)
return r;
enumerator->scan_uptodate = false;
return 0;
}
_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *_property, const char *_value) {
int r;
if (r < 0)
return r;
if (!property)
return -ENOMEM;
if (_value) {
if (!value)
return -ENOMEM;
}
if (r < 0)
return r;
enumerator->scan_uptodate = false;
return 0;
}
_public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
int r;
if (r < 0)
return r;
if (r < 0)
return r;
enumerator->scan_uptodate = false;
return 0;
}
_public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
int r;
if (r < 0)
return r;
if (r < 0)
return r;
enumerator->scan_uptodate = false;
return 0;
}
_public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
enumerator->scan_uptodate = false;
return 0;
}
enumerator->match_allow_uninitialized = true;
enumerator->scan_uptodate = false;
return 0;
}
enumerator->match_allow_uninitialized = false;
enumerator->scan_uptodate = false;
return 0;
}
if (sound_a) {
/* For sound cards the control device must be enumerated last to
* make sure it's the final device node that gets ACLs applied.
* Applications rely on this fact and use ACL changes on the
* control node as an indicator that the ACL change of the
* entire sound card completed. The kernel makes this guarantee
* when creating those devices, and hence we should too when
* enumerating them. */
if (sound_a) {
unsigned prefix_len;
const char *sound_b;
return 1;
return -1;
}
}
}
/* md and dm devices are enumerated after all other devices */
}
int r;
if (r < 0)
return r;
if (r < 0)
return r;
return 0;
}
const char *value;
int r;
if (r < 0)
return false;
if (!match_value)
return true;
return true;
return false;
}
const char *sysattr;
const char *value;
Iterator i;
return false;
return false;
return true;
}
const char *property;
const char *value;
Iterator i;
return true;
const char *property_dev, *value_dev;
continue;
return true;
continue;
return true;
}
}
return false;
}
const char *tag;
Iterator i;
return false;
return true;
}
const char *devpath, *devpath_dev;
int r;
if (!enumerator->match_parent)
return true;
assert(r >= 0);
assert(r >= 0);
}
const char *sysname_match;
Iterator i;
return true;
return true;
return false;
}
static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
char *path;
int r = 0;
if (subdir1)
if (subdir2)
if (!dir)
return -errno;
int ifindex, initialized, k;
continue;
continue;
if (k < 0) {
if (k != -ENODEV)
/* this is necessarily racey, so ignore missing devices */
r = k;
continue;
}
if (k < 0) {
r = k;
continue;
}
if (k < 0) {
r = k;
continue;
}
if (k < 0) {
r = k;
continue;
}
/*
* All devices with a device node or network interfaces
* possibly need udev to adjust the device node permission
* or context, or rename the interface before it can be
* reliably used from other processes.
*
* For now, we can only check these types of devices, we
* might not store a database, and have no way to find out
* for all other types of devices.
*/
if (!enumerator->match_allow_uninitialized &&
!initialized &&
continue;
continue;
continue;
continue;
continue;
if (k < 0)
r = k;
}
return r;
}
const char *subsystem_match;
Iterator i;
if (!subsystem)
return false;
return false;
return true;
return true;
return false;
}
static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
char *path;
int r = 0;
if (!dir)
return -errno;
int k;
continue;
continue;
if (k < 0)
r = k;
}
return r;
}
char *path;
int r = 0;
if (!dir) {
return 0;
else {
return -errno;
}
}
/* TODO: filter away subsystems? */
int k;
continue;
if (k < 0) {
if (k != -ENODEV)
/* this is necessarily racy, so ignore missing devices */
r = k;
continue;
}
if (k < 0) {
r = k;
continue;
}
continue;
if (k < 0) {
r = k;
continue;
}
continue;
continue;
continue;
continue;
if (k < 0) {
r = k;
continue;
}
}
return r;
}
const char *tag;
Iterator i;
int r;
if (r < 0)
return r;
}
return 0;
}
int r;
if (r == -ENODEV)
/* this is necessarily racy, so ignore missing devices */
return 0;
else if (r < 0)
return r;
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
return 0;
if (r < 0)
return r;
return 0;
return 0;
return 0;
if (r < 0)
return r;
return 1;
}
static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
int r = 0;
if (!dir) {
return -errno;
}
int k;
continue;
continue;
if (!child)
return -ENOMEM;
if (k < 0)
r = k;
if (maxdepth > 0)
else
}
return r;
}
const char *path;
int r = 0, k;
if (r < 0)
return r;
if (k < 0)
r = k;
if (k < 0)
r = k;
return r;
}
int r = 0;
log_debug("device-enumerator: scan all dirs");
/* we have /subsystem/, forget all the old stuff */
if (r < 0)
return log_debug_errno(r, "device-enumerator: failed to scan /sys/subsystem: %m");
} else {
int k;
if (k < 0) {
log_debug_errno(k, "device-enumerator: failed to scan /sys/bus: %m");
r = k;
}
if (k < 0) {
log_debug_errno(k, "device-enumerator: failed to scan /sys/class: %m");
r = k;
}
}
return r;
}
int r;
if (enumerator->scan_uptodate &&
return 0;
if (r < 0)
return r;
} else if (enumerator->match_parent) {
if (r < 0)
return r;
} else {
if (r < 0)
return r;
}
enumerator->scan_uptodate = true;
return 0;
}
int r;
if (r < 0)
return NULL;
}
if (!enumerator->scan_uptodate ||
return NULL;
}
const char *subsysdir;
int r = 0, k;
if (enumerator->scan_uptodate &&
return 0;
/* modules */
if (k < 0) {
log_debug_errno(k, "device-enumerator: failed to scan modules: %m");
r = k;
}
}
subsysdir = "subsystem";
else
subsysdir = "bus";
/* subsystems (only buses support coldplug) */
if (k < 0) {
log_debug_errno(k, "device-enumerator: failed to scan subsystems: %m");
r = k;
}
}
/* subsystem drivers */
if (k < 0) {
log_debug_errno(k, "device-enumerator: failed to scan drivers: %m");
r = k;
}
}
enumerator->scan_uptodate = true;
return r;
}
int r;
if (r < 0)
return NULL;
}
if (enumerator->scan_uptodate ||
return NULL;
}
}
}