mirror of
https://github.com/systemd/systemd.git
synced 2026-08-05 07:30:30 +00:00
libudev: make libudev-enumerate a thin wrapper around sd-device
This commit is contained in:
@@ -3976,8 +3976,8 @@ test_libudev_SOURCES = \
|
||||
test_libudev_LDADD = \
|
||||
libsystemd-label.la \
|
||||
libudev-internal.la \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-internal.la
|
||||
libsystemd-internal.la \
|
||||
libsystemd-shared.la
|
||||
|
||||
test_udev_SOURCES = \
|
||||
src/test/test-udev.c
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "libudev.h"
|
||||
#include "libudev-private.h"
|
||||
#include "sd-device.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
|
||||
Copyright 2015 Tom Gundersen <teg@jklm.no>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -28,7 +29,11 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "libudev.h"
|
||||
#include "libudev-private.h"
|
||||
#include "libudev-device-internal.h"
|
||||
#include "sd-device.h"
|
||||
#include "device-util.h"
|
||||
#include "device-enumerator-private.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:libudev-enumerate
|
||||
@@ -38,11 +43,6 @@
|
||||
* and return a sorted list of devices.
|
||||
*/
|
||||
|
||||
struct syspath {
|
||||
char *syspath;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* udev_enumerate:
|
||||
*
|
||||
@@ -51,20 +51,10 @@ struct syspath {
|
||||
struct udev_enumerate {
|
||||
struct udev *udev;
|
||||
int refcount;
|
||||
struct udev_list sysattr_match_list;
|
||||
struct udev_list sysattr_nomatch_list;
|
||||
struct udev_list subsystem_match_list;
|
||||
struct udev_list subsystem_nomatch_list;
|
||||
struct udev_list sysname_match_list;
|
||||
struct udev_list properties_match_list;
|
||||
struct udev_list tags_match_list;
|
||||
struct udev_device *parent_match;
|
||||
struct udev_list devices_list;
|
||||
struct syspath *devices;
|
||||
unsigned int devices_cur;
|
||||
unsigned int devices_max;
|
||||
bool devices_uptodate:1;
|
||||
bool match_is_initialized;
|
||||
|
||||
sd_device_enumerator *enumerator;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -75,25 +65,30 @@ struct udev_enumerate {
|
||||
*
|
||||
* Returns: an enumeration context.
|
||||
**/
|
||||
_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
|
||||
{
|
||||
_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
|
||||
struct udev_enumerate *udev_enumerate;
|
||||
int r;
|
||||
|
||||
assert_return_errno(udev, NULL, EINVAL);
|
||||
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
udev_enumerate = new0(struct udev_enumerate, 1);
|
||||
if (udev_enumerate == NULL)
|
||||
if (!udev_enumerate) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = sd_device_enumerator_new(&udev_enumerate->enumerator);
|
||||
if (r < 0) {
|
||||
free(udev_enumerate);
|
||||
errno = -r;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
udev_enumerate->refcount = 1;
|
||||
udev_enumerate->udev = udev;
|
||||
udev_list_init(udev, &udev_enumerate->sysattr_match_list, false);
|
||||
udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false);
|
||||
udev_list_init(udev, &udev_enumerate->subsystem_match_list, true);
|
||||
udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true);
|
||||
udev_list_init(udev, &udev_enumerate->sysname_match_list, true);
|
||||
udev_list_init(udev, &udev_enumerate->properties_match_list, false);
|
||||
udev_list_init(udev, &udev_enumerate->tags_match_list, true);
|
||||
|
||||
udev_list_init(udev, &udev_enumerate->devices_list, false);
|
||||
|
||||
return udev_enumerate;
|
||||
}
|
||||
|
||||
@@ -105,11 +100,10 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
|
||||
*
|
||||
* Returns: the passed enumeration context
|
||||
**/
|
||||
_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return NULL;
|
||||
udev_enumerate->refcount++;
|
||||
_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
|
||||
if (udev_enumerate)
|
||||
udev_enumerate->refcount ++;
|
||||
|
||||
return udev_enumerate;
|
||||
}
|
||||
|
||||
@@ -122,28 +116,13 @@ _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_e
|
||||
*
|
||||
* Returns: #NULL
|
||||
**/
|
||||
_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
unsigned int i;
|
||||
_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) {
|
||||
if (udev_enumerate && (-- udev_enumerate->refcount) == 0) {
|
||||
udev_list_cleanup(&udev_enumerate->devices_list);
|
||||
sd_device_enumerator_unref(udev_enumerate->enumerator);
|
||||
free(udev_enumerate);
|
||||
}
|
||||
|
||||
if (udev_enumerate == NULL)
|
||||
return NULL;
|
||||
udev_enumerate->refcount--;
|
||||
if (udev_enumerate->refcount > 0)
|
||||
return NULL;
|
||||
udev_list_cleanup(&udev_enumerate->sysattr_match_list);
|
||||
udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list);
|
||||
udev_list_cleanup(&udev_enumerate->subsystem_match_list);
|
||||
udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list);
|
||||
udev_list_cleanup(&udev_enumerate->sysname_match_list);
|
||||
udev_list_cleanup(&udev_enumerate->properties_match_list);
|
||||
udev_list_cleanup(&udev_enumerate->tags_match_list);
|
||||
udev_device_unref(udev_enumerate->parent_match);
|
||||
udev_list_cleanup(&udev_enumerate->devices_list);
|
||||
for (i = 0; i < udev_enumerate->devices_cur; i++)
|
||||
free(udev_enumerate->devices[i].syspath);
|
||||
free(udev_enumerate->devices);
|
||||
free(udev_enumerate);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -155,105 +134,12 @@ _public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev
|
||||
*
|
||||
* Returns: a pointer to the context.
|
||||
*/
|
||||
_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return NULL;
|
||||
_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
|
||||
assert_return_errno(udev_enumerate, NULL, EINVAL);
|
||||
|
||||
return udev_enumerate->udev;
|
||||
}
|
||||
|
||||
static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
|
||||
{
|
||||
char *path;
|
||||
struct syspath *entry;
|
||||
|
||||
/* double array size if needed */
|
||||
if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
|
||||
struct syspath *buf;
|
||||
unsigned int add;
|
||||
|
||||
add = udev_enumerate->devices_max;
|
||||
if (add < 1024)
|
||||
add = 1024;
|
||||
buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
udev_enumerate->devices = buf;
|
||||
udev_enumerate->devices_max += add;
|
||||
}
|
||||
|
||||
path = strdup(syspath);
|
||||
if (path == NULL)
|
||||
return -ENOMEM;
|
||||
entry = &udev_enumerate->devices[udev_enumerate->devices_cur];
|
||||
entry->syspath = path;
|
||||
entry->len = strlen(path);
|
||||
udev_enumerate->devices_cur++;
|
||||
udev_enumerate->devices_uptodate = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int syspath_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct syspath *path1 = p1;
|
||||
const struct syspath *path2 = p2;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
len = MIN(path1->len, path2->len);
|
||||
ret = memcmp(path1->syspath, path2->syspath, len);
|
||||
if (ret == 0) {
|
||||
if (path1->len < path2->len)
|
||||
ret = -1;
|
||||
else if (path1->len > path2->len)
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* For devices that should be moved to the absolute end of the list */
|
||||
static bool devices_delay_end(struct udev *udev, const char *syspath)
|
||||
{
|
||||
static const char *delay_device_list[] = {
|
||||
"/block/md",
|
||||
"/block/dm-",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; delay_device_list[i] != NULL; i++) {
|
||||
if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != NULL)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For devices that should just be moved a little bit later, just
|
||||
* before the point where some common path prefix changes. Returns the
|
||||
* number of characters that make up that common prefix */
|
||||
static size_t devices_delay_later(struct udev *udev, const char *syspath)
|
||||
{
|
||||
const char *c;
|
||||
|
||||
/* 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 ((c = strstr(syspath, "/sound/card"))) {
|
||||
c += 11;
|
||||
c += strcspn(c, "/");
|
||||
|
||||
if (startswith(c, "/controlC"))
|
||||
return c - syspath + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_enumerate_get_list_entry:
|
||||
* @udev_enumerate: context
|
||||
@@ -262,77 +148,30 @@ static size_t devices_delay_later(struct udev *udev, const char *syspath)
|
||||
*
|
||||
* Returns: a udev_list_entry.
|
||||
*/
|
||||
_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return NULL;
|
||||
_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
|
||||
assert_return_errno(udev_enumerate, NULL, EINVAL);
|
||||
|
||||
if (!udev_enumerate->devices_uptodate) {
|
||||
unsigned int i;
|
||||
int move_later = -1;
|
||||
unsigned int max;
|
||||
struct syspath *prev = NULL;
|
||||
size_t move_later_prefix = 0;
|
||||
sd_device *device;
|
||||
|
||||
udev_list_cleanup(&udev_enumerate->devices_list);
|
||||
qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
|
||||
|
||||
max = udev_enumerate->devices_cur;
|
||||
for (i = 0; i < max; i++) {
|
||||
struct syspath *entry = &udev_enumerate->devices[i];
|
||||
FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) {
|
||||
const char *syspath;
|
||||
int r;
|
||||
|
||||
/* skip duplicated entries */
|
||||
if (prev != NULL &&
|
||||
entry->len == prev->len &&
|
||||
memcmp(entry->syspath, prev->syspath, entry->len) == 0)
|
||||
continue;
|
||||
prev = entry;
|
||||
|
||||
/* skip to be delayed devices, and add them to the end of the list */
|
||||
if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
|
||||
syspath_add(udev_enumerate, entry->syspath);
|
||||
/* need to update prev here for the case realloc() gives a different address */
|
||||
prev = &udev_enumerate->devices[i];
|
||||
continue;
|
||||
r = sd_device_get_syspath(device, &syspath);
|
||||
if (r < 0) {
|
||||
errno = -r;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* skip to be delayed devices, and move the to
|
||||
* the point where the prefix changes. We can
|
||||
* only move one item at a time. */
|
||||
if (move_later == -1) {
|
||||
move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
|
||||
|
||||
if (move_later_prefix > 0) {
|
||||
move_later = i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((move_later >= 0) &&
|
||||
!strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) {
|
||||
|
||||
udev_list_entry_add(&udev_enumerate->devices_list,
|
||||
udev_enumerate->devices[move_later].syspath, NULL);
|
||||
move_later = -1;
|
||||
}
|
||||
|
||||
udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
|
||||
udev_list_entry_add(&udev_enumerate->devices_list, syspath, NULL);
|
||||
}
|
||||
|
||||
if (move_later >= 0)
|
||||
udev_list_entry_add(&udev_enumerate->devices_list,
|
||||
udev_enumerate->devices[move_later].syspath, NULL);
|
||||
|
||||
/* add and cleanup delayed devices from end of list */
|
||||
for (i = max; i < udev_enumerate->devices_cur; i++) {
|
||||
struct syspath *entry = &udev_enumerate->devices[i];
|
||||
|
||||
udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
|
||||
free(entry->syspath);
|
||||
}
|
||||
udev_enumerate->devices_cur = max;
|
||||
|
||||
udev_enumerate->devices_uptodate = true;
|
||||
}
|
||||
|
||||
return udev_list_get_entry(&udev_enumerate->devices_list);
|
||||
}
|
||||
|
||||
@@ -345,15 +184,10 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (subsystem == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,15 +199,10 @@ _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (subsystem == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,15 +215,10 @@ _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_en
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (sysattr == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -407,35 +231,10 @@ _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumer
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (sysattr == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
|
||||
{
|
||||
const char *val = NULL;
|
||||
bool match = false;
|
||||
|
||||
val = udev_device_get_sysattr_value(dev, sysattr);
|
||||
if (val == NULL)
|
||||
goto exit;
|
||||
if (match_val == NULL) {
|
||||
match = true;
|
||||
goto exit;
|
||||
}
|
||||
if (fnmatch(match_val, val, 0) == 0) {
|
||||
match = true;
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
return match;
|
||||
return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -448,15 +247,10 @@ exit:
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (property == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
return sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,15 +262,10 @@ _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enume
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (tag == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
return sd_device_enumerator_add_match_tag(udev_enumerate->enumerator, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,16 +281,13 @@ _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate,
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (parent == NULL)
|
||||
_public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
if (!parent)
|
||||
return 0;
|
||||
if (udev_enumerate->parent_match != NULL)
|
||||
udev_device_unref(udev_enumerate->parent_match);
|
||||
udev_enumerate->parent_match = udev_device_ref(parent);
|
||||
return 0;
|
||||
|
||||
return sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, parent->device);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -522,12 +308,10 @@ _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumera
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
udev_enumerate->match_is_initialized = true;
|
||||
return 0;
|
||||
_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
return sd_device_enumerator_add_match_is_initialized(udev_enumerate->enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -539,224 +323,10 @@ _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (sysname == NULL)
|
||||
return 0;
|
||||
if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
/* skip list */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
|
||||
if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry)))
|
||||
return false;
|
||||
}
|
||||
/* include list */
|
||||
if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
|
||||
/* anything that does not match, will make it FALSE */
|
||||
if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
bool match = false;
|
||||
|
||||
/* no match always matches */
|
||||
if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
|
||||
return true;
|
||||
|
||||
/* loop over matches */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
|
||||
const char *match_key = udev_list_entry_get_name(list_entry);
|
||||
const char *match_value = udev_list_entry_get_value(list_entry);
|
||||
struct udev_list_entry *property_entry;
|
||||
|
||||
/* loop over device properties */
|
||||
udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
|
||||
const char *dev_key = udev_list_entry_get_name(property_entry);
|
||||
const char *dev_value = udev_list_entry_get_value(property_entry);
|
||||
|
||||
if (fnmatch(match_key, dev_key, 0) != 0)
|
||||
continue;
|
||||
if (match_value == NULL && dev_value == NULL) {
|
||||
match = true;
|
||||
goto out;
|
||||
}
|
||||
if (match_value == NULL || dev_value == NULL)
|
||||
continue;
|
||||
if (fnmatch(match_value, dev_value, 0) == 0) {
|
||||
match = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
return match;
|
||||
}
|
||||
|
||||
static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
/* no match always matches */
|
||||
if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
|
||||
return true;
|
||||
|
||||
/* loop over matches */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
|
||||
if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
|
||||
{
|
||||
if (udev_enumerate->parent_match == NULL)
|
||||
return true;
|
||||
|
||||
return startswith(udev_device_get_devpath(dev), udev_device_get_devpath(udev_enumerate->parent_match));
|
||||
}
|
||||
|
||||
static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
|
||||
return true;
|
||||
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
|
||||
if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
|
||||
const char *basedir, const char *subdir1, const char *subdir2)
|
||||
{
|
||||
char path[UTIL_PATH_SIZE];
|
||||
size_t l;
|
||||
char *s;
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
|
||||
s = path;
|
||||
l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL);
|
||||
if (subdir1 != NULL)
|
||||
l = strpcpyl(&s, l, "/", subdir1, NULL);
|
||||
if (subdir2 != NULL)
|
||||
strpcpyl(&s, l, "/", subdir2, NULL);
|
||||
dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
return -ENOENT;
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
char syspath[UTIL_PATH_SIZE];
|
||||
struct udev_device *dev;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (!match_sysname(udev_enumerate, dent->d_name))
|
||||
continue;
|
||||
|
||||
strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
|
||||
dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
|
||||
if (dev == NULL)
|
||||
continue;
|
||||
|
||||
if (udev_enumerate->match_is_initialized) {
|
||||
/*
|
||||
* 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 (!udev_device_get_is_initialized(dev) &&
|
||||
(major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
|
||||
goto nomatch;
|
||||
}
|
||||
if (!match_parent(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_tag(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_property(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_sysattr(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
|
||||
syspath_add(udev_enumerate, udev_device_get_syspath(dev));
|
||||
nomatch:
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
if (!subsystem)
|
||||
return false;
|
||||
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
|
||||
if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
|
||||
if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
|
||||
{
|
||||
char path[UTIL_PATH_SIZE];
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
|
||||
strscpyl(path, sizeof(path), "/sys/", basedir, NULL);
|
||||
dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
return -1;
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
|
||||
continue;
|
||||
scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
return sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -768,141 +338,23 @@ static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir,
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
*/
|
||||
_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
|
||||
_cleanup_device_unref_ sd_device *device = NULL;
|
||||
int r;
|
||||
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
if (syspath == NULL)
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
if (!syspath)
|
||||
return 0;
|
||||
/* resolve to real syspath */
|
||||
udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
|
||||
if (udev_device == NULL)
|
||||
return -EINVAL;
|
||||
syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
|
||||
udev_device_unref(udev_device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
struct udev_list_entry *list_entry;
|
||||
r = sd_device_new_from_syspath(&device, syspath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
char path[UTIL_PATH_SIZE];
|
||||
r = sd_device_enumerator_add_device(udev_enumerate->enumerator, device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
strscpyl(path, sizeof(path), "/run/udev/tags/", udev_list_entry_get_name(list_entry), NULL);
|
||||
dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
continue;
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
struct udev_device *dev;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name);
|
||||
if (dev == NULL)
|
||||
continue;
|
||||
|
||||
if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev)))
|
||||
goto nomatch;
|
||||
if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev)))
|
||||
goto nomatch;
|
||||
if (!match_parent(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_property(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_sysattr(udev_enumerate, dev))
|
||||
goto nomatch;
|
||||
|
||||
syspath_add(udev_enumerate, udev_device_get_syspath(dev));
|
||||
nomatch:
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parent_add_child(struct udev_enumerate *enumerate, const char *path)
|
||||
{
|
||||
struct udev_device *dev;
|
||||
int r = 0;
|
||||
|
||||
dev = udev_device_new_from_syspath(enumerate->udev, path);
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
|
||||
goto nomatch;
|
||||
if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
|
||||
goto nomatch;
|
||||
if (!match_property(enumerate, dev))
|
||||
goto nomatch;
|
||||
if (!match_sysattr(enumerate, dev))
|
||||
goto nomatch;
|
||||
|
||||
syspath_add(enumerate, udev_device_get_syspath(dev));
|
||||
r = 1;
|
||||
|
||||
nomatch:
|
||||
udev_device_unref(dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dent;
|
||||
|
||||
d = opendir(path);
|
||||
if (d == NULL)
|
||||
return -errno;
|
||||
|
||||
for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
|
||||
char *child;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
if (asprintf(&child, "%s/%s", path, dent->d_name) < 0)
|
||||
continue;
|
||||
parent_add_child(enumerate, child);
|
||||
if (maxdepth > 0)
|
||||
parent_crawl_children(enumerate, child, maxdepth-1);
|
||||
free(child);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_devices_children(struct udev_enumerate *enumerate)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
path = udev_device_get_syspath(enumerate->parent_match);
|
||||
parent_add_child(enumerate, path);
|
||||
return parent_crawl_children(enumerate, path, 256);
|
||||
}
|
||||
|
||||
static int scan_devices_all(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat("/sys/subsystem", &statbuf) == 0) {
|
||||
/* we have /subsystem/, forget all the old stuff */
|
||||
scan_dir(udev_enumerate, "subsystem", "devices", NULL);
|
||||
} else {
|
||||
scan_dir(udev_enumerate, "bus", "devices", NULL);
|
||||
scan_dir(udev_enumerate, "class", NULL, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -915,21 +367,10 @@ static int scan_devices_all(struct udev_enumerate *udev_enumerate)
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
**/
|
||||
_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
/* efficiently lookup tags only, we maintain a reverse-index */
|
||||
if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
|
||||
return scan_devices_tags(udev_enumerate);
|
||||
|
||||
/* walk the subtree of one parent device only */
|
||||
if (udev_enumerate->parent_match != NULL)
|
||||
return scan_devices_children(udev_enumerate);
|
||||
|
||||
/* scan devices of all subsystems */
|
||||
return scan_devices_all(udev_enumerate);
|
||||
return device_enumerator_scan_devices(udev_enumerate->enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -940,29 +381,8 @@ _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
|
||||
*
|
||||
* Returns: 0 on success, otherwise a negative error value.
|
||||
**/
|
||||
_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
|
||||
{
|
||||
struct stat statbuf;
|
||||
const char *subsysdir;
|
||||
_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
|
||||
assert_return(udev_enumerate, -EINVAL);
|
||||
|
||||
if (udev_enumerate == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* all kernel modules */
|
||||
if (match_subsystem(udev_enumerate, "module"))
|
||||
scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
|
||||
|
||||
if (stat("/sys/subsystem", &statbuf) == 0)
|
||||
subsysdir = "subsystem";
|
||||
else
|
||||
subsysdir = "bus";
|
||||
|
||||
/* all subsystems (only buses support coldplug) */
|
||||
if (match_subsystem(udev_enumerate, "subsystem"))
|
||||
scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
|
||||
|
||||
/* all subsystem drivers */
|
||||
if (match_subsystem(udev_enumerate, "drivers"))
|
||||
scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
|
||||
return 0;
|
||||
return device_enumerator_scan_subsystems(udev_enumerate->enumerator);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user