libudev-enumerate.c revision c32eb440bab953a0169cd207dfef5cad16dfb340
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering/***
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering This file is part of systemd.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Copyright 2015 Tom Gundersen <teg@jklm.no>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering (at your option) any later version.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering systemd is distributed in the hope that it will be useful, but
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Lesser General Public License for more details.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering***/
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <stdio.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <stdlib.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <stddef.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <errno.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <string.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <dirent.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <fnmatch.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <stdbool.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <sys/stat.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "libudev.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "libudev-device-internal.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "sd-device.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "device-util.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "device-enumerator-private.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering/**
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * SECTION:libudev-enumerate
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * @short_description: lookup and sort sys devices
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering *
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * Lookup devices in the sys filesystem, filter devices by properties,
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * and return a sorted list of devices.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering */
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering/**
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * udev_enumerate:
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering *
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * Opaque object representing one device lookup/sort context.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering */
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poetteringstruct udev_enumerate {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering struct udev *udev;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering int refcount;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering struct udev_list devices_list;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering bool devices_uptodate:1;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering sd_device_enumerator *enumerator;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering};
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering/**
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * udev_enumerate_new:
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * @udev: udev library context
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering *
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * Create an enumeration context to scan /sys.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering *
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering * Returns: an enumeration context.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering **/
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering struct udev_enumerate *udev_enumerate;
int r;
assert_return_errno(udev, NULL, EINVAL);
udev_enumerate = new0(struct udev_enumerate, 1);
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->devices_list, false);
return udev_enumerate;
}
/**
* udev_enumerate_ref:
* @udev_enumerate: context
*
* Take a reference of a enumeration context.
*
* Returns: the passed enumeration context
**/
_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
if (udev_enumerate)
udev_enumerate->refcount ++;
return udev_enumerate;
}
/**
* udev_enumerate_unref:
* @udev_enumerate: context
*
* Drop a reference of an enumeration context. If the refcount reaches zero,
* all resources of the enumeration context will be released.
*
* Returns: #NULL
**/
_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);
}
return NULL;
}
/**
* udev_enumerate_get_udev:
* @udev_enumerate: context
*
* Get the udev library context.
*
* Returns: a pointer to the context.
*/
_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
assert_return_errno(udev_enumerate, NULL, EINVAL);
return udev_enumerate->udev;
}
/**
* udev_enumerate_get_list_entry:
* @udev_enumerate: context
*
* Get the first entry of the sorted list of device paths.
*
* Returns: a udev_list_entry.
*/
_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) {
sd_device *device;
udev_list_cleanup(&udev_enumerate->devices_list);
FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) {
const char *syspath;
int r;
r = sd_device_get_syspath(device, &syspath);
if (r < 0) {
errno = -r;
return NULL;
}
udev_list_entry_add(&udev_enumerate->devices_list, syspath, NULL);
}
udev_enumerate->devices_uptodate = true;
}
return udev_list_get_entry(&udev_enumerate->devices_list);
}
/**
* udev_enumerate_add_match_subsystem:
* @udev_enumerate: context
* @subsystem: filter for a subsystem of the device to include in the list
*
* Match only devices belonging to a certain kernel subsystem.
*
* Returns: 0 on success, otherwise a negative error value.
*/
_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);
}
/**
* udev_enumerate_add_nomatch_subsystem:
* @udev_enumerate: context
* @subsystem: filter for a subsystem of the device to exclude from the list
*
* Match only devices not belonging to a certain kernel subsystem.
*
* Returns: 0 on success, otherwise a negative error value.
*/
_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);
}
/**
* udev_enumerate_add_match_sysattr:
* @udev_enumerate: context
* @sysattr: filter for a sys attribute at the device to include in the list
* @value: optional value of the sys attribute
*
* Match only devices with a certain /sys device attribute.
*
* 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) {
assert_return(udev_enumerate, -EINVAL);
return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true);
}
/**
* udev_enumerate_add_nomatch_sysattr:
* @udev_enumerate: context
* @sysattr: filter for a sys attribute at the device to exclude from the list
* @value: optional value of the sys attribute
*
* Match only devices not having a certain /sys device attribute.
*
* 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) {
assert_return(udev_enumerate, -EINVAL);
return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false);
}
/**
* udev_enumerate_add_match_property:
* @udev_enumerate: context
* @property: filter for a property of the device to include in the list
* @value: value of the property
*
* Match only devices with a certain property.
*
* 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) {
assert_return(udev_enumerate, -EINVAL);
return sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value);
}
/**
* udev_enumerate_add_match_tag:
* @udev_enumerate: context
* @tag: filter for a tag of the device to include in the list
*
* Match only devices with a certain tag.
*
* Returns: 0 on success, otherwise a negative error value.
*/
_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);
}
/**
* udev_enumerate_add_match_parent:
* @udev_enumerate: context
* @parent: parent device where to start searching
*
* Return the devices on the subtree of one given device. The parent
* itself is included in the list.
*
* A reference for the device is held until the udev_enumerate context
* is cleaned up.
*
* 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) {
assert_return(udev_enumerate, -EINVAL);
if (!parent)
return 0;
return sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, parent->device);
}
/**
* udev_enumerate_add_match_is_initialized:
* @udev_enumerate: context
*
* Match only devices which udev has set up already. This makes
* sure, that the device node permissions and context are properly set
* and that network devices are fully renamed.
*
* Usually, devices which are found in the kernel but not already
* handled by udev, have still pending events. Services should subscribe
* to monitor events and wait for these devices to become ready, instead
* of using uninitialized devices.
*
* For now, this will not affect devices which do not have a device node
* and are not network interfaces.
*
* Returns: 0 on success, otherwise a negative error value.
*/
_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);
}
/**
* udev_enumerate_add_match_sysname:
* @udev_enumerate: context
* @sysname: filter for the name of the device to include in the list
*
* Match only devices with a given /sys device name.
*
* Returns: 0 on success, otherwise a negative error value.
*/
_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
assert_return(udev_enumerate, -EINVAL);
return sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname);
}
/**
* udev_enumerate_add_syspath:
* @udev_enumerate: context
* @syspath: path of a device
*
* Add a device to the list of devices, to retrieve it back sorted in dependency order.
*
* Returns: 0 on success, otherwise a negative error value.
*/
_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
_cleanup_device_unref_ sd_device *device = NULL;
int r;
assert_return(udev_enumerate, -EINVAL);
if (!syspath)
return 0;
r = sd_device_new_from_syspath(&device, syspath);
if (r < 0)
return r;
r = sd_device_enumerator_add_device(udev_enumerate->enumerator, device);
if (r < 0)
return r;
return 0;
}
/**
* udev_enumerate_scan_devices:
* @udev_enumerate: udev enumeration context
*
* Scan /sys for all devices which match the given filters. No matches
* will return all currently available devices.
*
* Returns: 0 on success, otherwise a negative error value.
**/
_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
assert_return(udev_enumerate, -EINVAL);
return device_enumerator_scan_devices(udev_enumerate->enumerator);
}
/**
* udev_enumerate_scan_subsystems:
* @udev_enumerate: udev enumeration context
*
* Scan /sys for all kernel subsystems, including buses, classes, drivers.
*
* Returns: 0 on success, otherwise a negative error value.
**/
_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
assert_return(udev_enumerate, -EINVAL);
return device_enumerator_scan_subsystems(udev_enumerate->enumerator);
}