2008-08-28 00:02:41 +04:00
/*
* libudev - interface to udev device information
*
* Copyright ( C ) 2008 Kay Sievers < kay . sievers @ vrfy . org >
*
2009-03-26 21:29:36 +03:00
* This library is free software ; you can redistribute it and / or
* modify it 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 .
2008-08-28 00:02:41 +04:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <stddef.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include <dirent.h>
2008-09-30 15:42:26 +04:00
# include <fnmatch.h>
2009-07-08 04:04:49 +04:00
# include <stdbool.h>
2008-08-28 00:02:41 +04:00
# include <sys/stat.h>
2009-07-08 04:04:49 +04:00
# include <sys/param.h>
2008-08-28 00:02:41 +04:00
# include "libudev.h"
# include "libudev-private.h"
2009-06-15 19:09:43 +04:00
/**
* SECTION : libudev - enumerate
* @ short_description : lookup and sort sys devices
*
* Lookup devices in the sys filesystem , filter devices by properties ,
2009-06-15 22:04:46 +04:00
* and return a sorted list of devices .
2009-06-15 19:09:43 +04:00
*/
2009-07-08 04:04:49 +04:00
struct syspath {
char * syspath ;
size_t len ;
} ;
2009-06-15 19:09:43 +04:00
/**
* udev_enumerate :
*
* Opaque object representing one device lookup / sort context .
*/
2008-09-25 15:20:27 +04:00
struct udev_enumerate {
struct udev * udev ;
int refcount ;
2008-10-20 20:12:36 +04:00
struct udev_list_node sysattr_match_list ;
struct udev_list_node sysattr_nomatch_list ;
2008-10-10 00:24:43 +04:00
struct udev_list_node subsystem_match_list ;
struct udev_list_node subsystem_nomatch_list ;
2009-07-23 02:02:28 +04:00
struct udev_list_node sysname_match_list ;
2008-12-29 09:42:19 +03:00
struct udev_list_node properties_match_list ;
2008-10-10 00:24:43 +04:00
struct udev_list_node devices_list ;
2009-07-08 04:04:49 +04:00
struct syspath * devices ;
unsigned int devices_cur ;
unsigned int devices_max ;
bool devices_uptodate : 1 ;
2008-09-25 15:20:27 +04:00
} ;
2008-09-30 15:42:26 +04:00
/**
* udev_enumerate_new :
* @ udev : udev library context
*
* Returns : an enumeration context
* */
struct udev_enumerate * udev_enumerate_new ( struct udev * udev )
{
struct udev_enumerate * udev_enumerate ;
2008-10-21 14:10:32 +04:00
udev_enumerate = calloc ( 1 , sizeof ( struct udev_enumerate ) ) ;
2008-09-30 15:42:26 +04:00
if ( udev_enumerate = = NULL )
return NULL ;
udev_enumerate - > refcount = 1 ;
udev_enumerate - > udev = udev ;
2008-10-20 20:12:36 +04:00
udev_list_init ( & udev_enumerate - > sysattr_match_list ) ;
udev_list_init ( & udev_enumerate - > sysattr_nomatch_list ) ;
2008-10-10 00:24:43 +04:00
udev_list_init ( & udev_enumerate - > subsystem_match_list ) ;
udev_list_init ( & udev_enumerate - > subsystem_nomatch_list ) ;
2009-07-23 02:02:28 +04:00
udev_list_init ( & udev_enumerate - > sysname_match_list ) ;
2008-12-29 09:42:19 +03:00
udev_list_init ( & udev_enumerate - > properties_match_list ) ;
2009-07-08 04:04:49 +04:00
udev_list_init ( & udev_enumerate - > devices_list ) ;
2008-09-30 15:42:26 +04:00
return udev_enumerate ;
}
2009-06-15 19:09:43 +04:00
/**
* udev_enumerate_ref :
* @ udev_enumerate : context
*
* Take a reference of a enumeration context .
*
* Returns : the passed enumeration context
* */
2008-09-25 15:20:27 +04:00
struct udev_enumerate * udev_enumerate_ref ( struct udev_enumerate * udev_enumerate )
{
if ( udev_enumerate = = NULL )
return NULL ;
udev_enumerate - > refcount + + ;
return udev_enumerate ;
}
2009-06-15 19:09:43 +04:00
/**
* 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 .
* */
2008-09-25 15:20:27 +04:00
void udev_enumerate_unref ( struct udev_enumerate * udev_enumerate )
{
2009-07-08 04:04:49 +04:00
unsigned int i ;
2008-09-25 15:20:27 +04:00
if ( udev_enumerate = = NULL )
return ;
udev_enumerate - > refcount - - ;
if ( udev_enumerate - > refcount > 0 )
return ;
2008-10-20 20:12:36 +04:00
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > sysattr_match_list ) ;
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > sysattr_nomatch_list ) ;
2008-10-18 21:27:38 +04:00
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > subsystem_match_list ) ;
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > subsystem_nomatch_list ) ;
2009-07-23 02:02:28 +04:00
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > sysname_match_list ) ;
2008-12-29 09:42:19 +03:00
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > properties_match_list ) ;
2009-07-08 04:04:49 +04:00
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > devices_list ) ;
for ( i = 0 ; i < udev_enumerate - > devices_cur ; i + + )
free ( udev_enumerate - > devices [ i ] . syspath ) ;
free ( udev_enumerate - > devices ) ;
2008-09-25 15:20:27 +04:00
free ( udev_enumerate ) ;
}
2009-06-15 19:09:43 +04:00
/**
* udev_enumerate_get_udev :
* @ udev_enumerate : context
*
* Returns : the udev library context .
*/
2008-09-28 19:39:31 +04:00
struct udev * udev_enumerate_get_udev ( struct udev_enumerate * udev_enumerate )
{
if ( udev_enumerate = = NULL )
return NULL ;
return udev_enumerate - > udev ;
}
2009-07-08 04:04:49 +04:00
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 ;
}
2009-07-28 01:24:27 +04:00
/* For devices that should be moved to the absolute end of the list */
static int devices_delay_end ( struct udev * udev , const char * syspath )
2009-07-08 04:04:49 +04:00
{
static const char * delay_device_list [ ] = {
" /block/md " ,
" /block/dm- " ,
NULL
} ;
size_t len ;
int i ;
len = strlen ( udev_get_sys_path ( udev ) ) ;
for ( i = 0 ; delay_device_list [ i ] ! = NULL ; i + + ) {
if ( strstr ( & syspath [ len ] , delay_device_list [ i ] ) ! = NULL ) {
dbg ( udev , " delaying: %s \n " , syspath ) ;
return 1 ;
}
}
return 0 ;
}
2009-07-28 01:24:27 +04:00
/* 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 ( strncmp ( c , " /controlC " , 9 ) = = 0 )
return c - syspath + 1 ;
}
return 0 ;
}
2009-06-15 22:04:46 +04:00
/**
* udev_enumerate_get_list_entry :
* @ udev_enumerate : context
*
* Returns : the first entry of the sorted list of device paths .
*/
2008-09-28 03:34:55 +04:00
struct udev_list_entry * udev_enumerate_get_list_entry ( struct udev_enumerate * udev_enumerate )
2008-09-25 15:20:27 +04:00
{
if ( udev_enumerate = = NULL )
return NULL ;
2009-07-08 04:04:49 +04:00
if ( ! udev_enumerate - > devices_uptodate ) {
unsigned int i ;
unsigned int max ;
2009-07-28 01:24:27 +04:00
struct syspath * prev = NULL , * move_later = NULL ;
2009-12-30 18:21:59 +03:00
size_t move_later_prefix = 0 ;
2009-07-08 04:04:49 +04:00
udev_list_cleanup_entries ( udev_enumerate - > udev , & udev_enumerate - > devices_list ) ;
qsort ( 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 ] ;
/* 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 */
2009-07-28 01:24:27 +04:00
if ( devices_delay_end ( udev_enumerate - > udev , entry - > syspath ) ) {
2009-07-08 04:04:49 +04:00
syspath_add ( udev_enumerate , entry - > syspath ) ;
continue ;
}
2009-07-28 01:24:27 +04:00
/* 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 ) {
move_later_prefix = devices_delay_later ( udev_enumerate - > udev , entry - > syspath ) ;
if ( move_later_prefix > 0 ) {
move_later = entry ;
continue ;
}
}
if ( move_later & &
strncmp ( entry - > syspath , move_later - > syspath , move_later_prefix ) ! = 0 ) {
udev_list_entry_add ( udev_enumerate - > udev , & udev_enumerate - > devices_list ,
move_later - > syspath , NULL , 0 , 0 ) ;
move_later = NULL ;
}
2009-07-08 04:04:49 +04:00
udev_list_entry_add ( udev_enumerate - > udev , & udev_enumerate - > devices_list ,
entry - > syspath , NULL , 0 , 0 ) ;
}
2009-07-28 01:24:27 +04:00
if ( move_later )
udev_list_entry_add ( udev_enumerate - > udev , & udev_enumerate - > devices_list ,
move_later - > syspath , NULL , 0 , 0 ) ;
2009-07-08 04:04:49 +04:00
/* 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 - > udev , & udev_enumerate - > devices_list ,
entry - > syspath , NULL , 0 , 0 ) ;
free ( entry - > syspath ) ;
}
udev_enumerate - > devices_cur = max ;
udev_enumerate - > devices_uptodate = true ;
}
2008-10-10 00:24:43 +04:00
return udev_list_get_entry ( & udev_enumerate - > devices_list ) ;
2008-09-25 15:20:27 +04:00
}
2009-06-15 22:04:46 +04:00
/**
* udev_enumerate_add_match_subsystem :
* @ udev_enumerate : context
* @ subsystem : filter for a subsystem of the device to include in the list
*
* Returns : 0 on success , otherwise a negative error value .
*/
2008-09-30 15:42:26 +04:00
int udev_enumerate_add_match_subsystem ( struct udev_enumerate * udev_enumerate , const char * subsystem )
2008-08-28 00:02:41 +04:00
{
2008-09-30 15:42:26 +04:00
if ( udev_enumerate = = NULL )
return - EINVAL ;
if ( subsystem = = NULL )
return 0 ;
2008-10-10 00:24:43 +04:00
if ( udev_list_entry_add ( udev_enumerate_get_udev ( udev_enumerate ) ,
& udev_enumerate - > subsystem_match_list , subsystem , NULL , 1 , 0 ) = = NULL )
2008-09-30 15:42:26 +04:00
return - ENOMEM ;
return 0 ;
}
2009-06-15 22:04:46 +04:00
/**
* udev_enumerate_add_nomatch_subsystem :
* @ udev_enumerate : context
* @ subsystem : filter for a subsystem of the device to exclude from the list
*
* Returns : 0 on success , otherwise a negative error value .
*/
2008-09-30 15:42:26 +04:00
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 ;
2008-10-10 00:24:43 +04:00
if ( udev_list_entry_add ( udev_enumerate_get_udev ( udev_enumerate ) ,
& udev_enumerate - > subsystem_nomatch_list , subsystem , NULL , 1 , 0 ) = = NULL )
2008-09-30 15:42:26 +04:00
return - ENOMEM ;
return 0 ;
}
2009-06-15 22:04:46 +04:00
/**
* 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
*
* Returns : 0 on success , otherwise a negative error value .
*/
2008-10-20 20:12:36 +04:00
int udev_enumerate_add_match_sysattr ( struct udev_enumerate * udev_enumerate , const char * sysattr , const char * value )
2008-09-30 15:42:26 +04:00
{
if ( udev_enumerate = = NULL )
return - EINVAL ;
2008-10-20 20:12:36 +04:00
if ( sysattr = = NULL )
2008-09-30 15:42:26 +04:00
return 0 ;
2008-10-10 00:24:43 +04:00
if ( udev_list_entry_add ( udev_enumerate_get_udev ( udev_enumerate ) ,
2009-06-07 03:51:38 +04:00
& udev_enumerate - > sysattr_match_list , sysattr , value , 0 , 0 ) = = NULL )
2008-09-30 15:42:26 +04:00
return - ENOMEM ;
return 0 ;
}
2009-06-15 22:04:46 +04:00
/**
* 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
*
* Returns : 0 on success , otherwise a negative error value .
*/
2008-10-20 20:12:36 +04:00
int udev_enumerate_add_nomatch_sysattr ( struct udev_enumerate * udev_enumerate , const char * sysattr , const char * value )
2008-09-30 15:42:26 +04:00
{
if ( udev_enumerate = = NULL )
return - EINVAL ;
2008-10-20 20:12:36 +04:00
if ( sysattr = = NULL )
2008-09-30 15:42:26 +04:00
return 0 ;
2008-10-10 00:24:43 +04:00
if ( udev_list_entry_add ( udev_enumerate_get_udev ( udev_enumerate ) ,
2009-06-07 03:51:38 +04:00
& udev_enumerate - > sysattr_nomatch_list , sysattr , value , 0 , 0 ) = = NULL )
2008-09-30 15:42:26 +04:00
return - ENOMEM ;
return 0 ;
}
2008-10-20 20:12:36 +04:00
static int match_sysattr_value ( struct udev * udev , const char * syspath , const char * sysattr , const char * match_val )
2008-09-30 15:42:26 +04:00
{
struct udev_device * device ;
const char * val = NULL ;
2009-07-08 04:04:49 +04:00
bool match = false ;
2008-09-30 15:42:26 +04:00
device = udev_device_new_from_syspath ( udev , syspath ) ;
if ( device = = NULL )
return - EINVAL ;
2008-10-20 20:12:36 +04:00
val = udev_device_get_sysattr_value ( device , sysattr ) ;
2008-09-30 15:42:26 +04:00
if ( val = = NULL )
goto exit ;
if ( match_val = = NULL ) {
2009-07-08 04:04:49 +04:00
match = true ;
2008-09-30 15:42:26 +04:00
goto exit ;
}
if ( fnmatch ( match_val , val , 0 ) = = 0 ) {
2009-07-08 04:04:49 +04:00
match = true ;
2008-09-30 15:42:26 +04:00
goto exit ;
}
exit :
udev_device_unref ( device ) ;
return match ;
}
2009-06-15 22:04:46 +04:00
/**
* 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
*
* Returns : 0 on success , otherwise a negative error value .
*/
2008-12-29 09:42:19 +03:00
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_get_udev ( udev_enumerate ) ,
2009-06-07 03:51:38 +04:00
& udev_enumerate - > properties_match_list , property , value , 0 , 0 ) = = NULL )
2008-12-29 09:42:19 +03:00
return - ENOMEM ;
return 0 ;
}
2009-07-23 02:02:28 +04:00
/**
* udev_enumerate_add_match_sysname :
* @ udev_enumerate : context
* @ sysname : filter for the name of the device to include in the list
*
* Returns : 0 on success , otherwise a negative error value .
*/
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_get_udev ( udev_enumerate ) ,
& udev_enumerate - > sysname_match_list , sysname , NULL , 1 , 0 ) = = NULL )
return - ENOMEM ;
return 0 ;
}
2008-10-20 20:12:36 +04:00
static int match_sysattr ( struct udev_enumerate * udev_enumerate , const char * syspath )
2008-09-30 15:42:26 +04:00
{
struct udev * udev = udev_enumerate_get_udev ( udev_enumerate ) ;
struct udev_list_entry * list_entry ;
/* skip list */
2008-10-20 20:12:36 +04:00
udev_list_entry_foreach ( list_entry , udev_list_get_entry ( & udev_enumerate - > sysattr_nomatch_list ) ) {
if ( match_sysattr_value ( udev , syspath ,
2008-09-30 15:42:26 +04:00
udev_list_entry_get_name ( list_entry ) ,
udev_list_entry_get_value ( list_entry ) ) )
return 0 ;
}
/* include list */
2008-10-20 20:12:36 +04:00
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 ) ) {
2008-09-30 15:42:26 +04:00
/* anything that does not match, will make it FALSE */
2008-10-20 20:12:36 +04:00
if ( ! match_sysattr_value ( udev , syspath ,
2008-09-30 15:42:26 +04:00
udev_list_entry_get_name ( list_entry ) ,
udev_list_entry_get_value ( list_entry ) ) )
return 0 ;
}
return 1 ;
}
return 1 ;
}
2008-12-29 09:42:19 +03:00
static int match_property ( struct udev_enumerate * udev_enumerate , const char * syspath )
{
struct udev_device * dev ;
struct udev_list_entry * list_entry ;
2009-07-08 04:04:49 +04:00
int match = false ;
2008-12-29 09:42:19 +03:00
/* no match always matches */
if ( udev_list_get_entry ( & udev_enumerate - > properties_match_list ) = = NULL )
return 1 ;
/* no device does not match */
dev = udev_device_new_from_syspath ( udev_enumerate - > udev , syspath ) ;
if ( dev = = NULL )
return 0 ;
/* loop over matches */
udev_list_entry_foreach ( list_entry , udev_list_get_entry ( & udev_enumerate - > properties_match_list ) ) {
2009-06-07 03:51:38 +04:00
const char * match_key = udev_list_entry_get_name ( list_entry ) ;
const char * match_value = udev_list_entry_get_value ( list_entry ) ;
2008-12-29 09:42:19 +03:00
struct udev_list_entry * property_entry ;
/* loop over device properties */
udev_list_entry_foreach ( property_entry , udev_device_get_properties_list_entry ( dev ) ) {
2009-06-07 03:51:38 +04:00
const char * dev_key = udev_list_entry_get_name ( property_entry ) ;
const char * dev_value = udev_list_entry_get_value ( property_entry ) ;
2008-12-29 09:42:19 +03:00
2009-06-07 03:51:38 +04:00
if ( fnmatch ( match_key , dev_key , 0 ) ! = 0 )
continue ;
if ( match_value = = NULL & & dev_value = = NULL ) {
2009-07-08 04:04:49 +04:00
match = true ;
2009-06-07 03:51:38 +04:00
goto out ;
}
if ( match_value = = NULL | | dev_value = = NULL )
continue ;
if ( fnmatch ( match_value , dev_value , 0 ) = = 0 ) {
2009-07-08 04:04:49 +04:00
match = true ;
2009-06-07 03:51:38 +04:00
goto out ;
2008-12-29 09:42:19 +03:00
}
}
}
out :
udev_device_unref ( dev ) ;
return match ;
}
2009-07-23 02:02:28 +04:00
static int 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 1 ;
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 1 ;
}
return 0 ;
}
2008-10-01 15:57:39 +04:00
static int scan_dir_and_add_devices ( struct udev_enumerate * udev_enumerate ,
const char * basedir , const char * subdir1 , const char * subdir2 )
2008-09-30 15:42:26 +04:00
{
struct udev * udev = udev_enumerate_get_udev ( udev_enumerate ) ;
2008-09-10 20:00:31 +04:00
char path [ UTIL_PATH_SIZE ] ;
2009-05-20 19:57:52 +04:00
size_t l ;
char * s ;
2008-08-28 00:02:41 +04:00
DIR * dir ;
struct dirent * dent ;
2009-05-20 19:57:52 +04:00
s = path ;
l = util_strpcpyl ( & s , sizeof ( path ) , udev_get_sys_path ( udev ) , " / " , basedir , NULL ) ;
if ( subdir1 ! = NULL )
l = util_strpcpyl ( & s , l , " / " , subdir1 , NULL ) ;
if ( subdir2 ! = NULL )
2009-09-09 00:11:04 +04:00
util_strpcpyl ( & s , l , " / " , subdir2 , NULL ) ;
2008-08-28 00:02:41 +04:00
dir = opendir ( path ) ;
if ( dir = = NULL )
return - 1 ;
for ( dent = readdir ( dir ) ; dent ! = NULL ; dent = readdir ( dir ) ) {
2008-09-16 04:12:47 +04:00
char syspath [ UTIL_PATH_SIZE ] ;
2008-09-29 01:17:29 +04:00
char filename [ UTIL_PATH_SIZE ] ;
2008-09-29 00:18:40 +04:00
struct stat statbuf ;
2008-08-28 00:02:41 +04:00
if ( dent - > d_name [ 0 ] = = ' . ' )
continue ;
2009-07-23 02:02:28 +04:00
if ( ! match_sysname ( udev_enumerate , dent - > d_name ) )
continue ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( syspath , sizeof ( syspath ) , path , " / " , dent - > d_name , NULL ) ;
2009-12-21 17:41:25 +03:00
if ( ! match_property ( udev_enumerate , syspath ) )
continue ;
2008-10-01 15:57:39 +04:00
if ( lstat ( syspath , & statbuf ) ! = 0 )
continue ;
if ( S_ISREG ( statbuf . st_mode ) )
continue ;
if ( S_ISLNK ( statbuf . st_mode ) )
util_resolve_sys_link ( udev , syspath , sizeof ( syspath ) ) ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( filename , sizeof ( filename ) , syspath , " /uevent " , NULL ) ;
2008-09-29 01:17:29 +04:00
if ( stat ( filename , & statbuf ) ! = 0 )
2008-09-29 00:18:40 +04:00
continue ;
2008-10-20 20:12:36 +04:00
if ( ! match_sysattr ( udev_enumerate , syspath ) )
2008-09-30 15:42:26 +04:00
continue ;
2009-07-08 04:04:49 +04:00
syspath_add ( udev_enumerate , syspath ) ;
2008-08-28 00:02:41 +04:00
}
closedir ( dir ) ;
return 0 ;
}
2008-09-30 15:42:26 +04:00
static int match_subsystem ( struct udev_enumerate * udev_enumerate , const char * subsystem )
2008-08-28 00:02:41 +04:00
{
2008-09-30 15:42:26 +04:00
struct udev_list_entry * list_entry ;
2008-10-10 00:24:43 +04:00
udev_list_entry_foreach ( list_entry , udev_list_get_entry ( & udev_enumerate - > subsystem_nomatch_list ) ) {
2008-09-30 15:42:26 +04:00
if ( fnmatch ( udev_list_entry_get_name ( list_entry ) , subsystem , 0 ) = = 0 )
return 0 ;
}
2008-10-10 00:24:43 +04:00
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 ) ) {
2008-09-30 15:42:26 +04:00
if ( fnmatch ( udev_list_entry_get_name ( list_entry ) , subsystem , 0 ) = = 0 )
return 1 ;
2008-09-28 19:39:31 +04:00
}
2008-09-30 15:42:26 +04:00
return 0 ;
2008-08-28 00:02:41 +04:00
}
2008-09-30 15:42:26 +04:00
return 1 ;
}
2008-10-01 15:57:39 +04:00
static int scan_dir ( struct udev_enumerate * udev_enumerate , const char * basedir , const char * subdir , const char * subsystem )
2008-09-30 15:42:26 +04:00
{
struct udev * udev = udev_enumerate_get_udev ( udev_enumerate ) ;
char path [ UTIL_PATH_SIZE ] ;
DIR * dir ;
struct dirent * dent ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , sizeof ( path ) , udev_get_sys_path ( udev ) , " / " , basedir , NULL ) ;
2008-09-30 15:42:26 +04:00
dir = opendir ( path ) ;
if ( dir = = NULL )
return - 1 ;
for ( dent = readdir ( dir ) ; dent ! = NULL ; dent = readdir ( dir ) ) {
if ( dent - > d_name [ 0 ] = = ' . ' )
continue ;
2008-10-01 15:57:39 +04:00
if ( ! match_subsystem ( udev_enumerate , subsystem ! = NULL ? subsystem : dent - > d_name ) )
2008-09-30 15:42:26 +04:00
continue ;
scan_dir_and_add_devices ( udev_enumerate , basedir , dent - > d_name , subdir ) ;
}
closedir ( dir ) ;
2008-08-28 00:02:41 +04:00
return 0 ;
}
2009-06-15 22:04:46 +04:00
/**
* 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 .
*/
2008-10-02 13:54:33 +04:00
int udev_enumerate_add_syspath ( struct udev_enumerate * udev_enumerate , const char * syspath )
{
struct udev_device * udev_device ;
2008-09-29 00:18:40 +04:00
if ( udev_enumerate = = NULL )
2008-09-30 15:42:26 +04:00
return - EINVAL ;
2008-10-02 13:54:33 +04:00
if ( syspath = = NULL )
2008-09-30 15:42:26 +04:00
return 0 ;
2008-10-02 13:54:33 +04:00
/* resolve to real syspath */
udev_device = udev_device_new_from_syspath ( udev_enumerate - > udev , syspath ) ;
if ( udev_device = = NULL )
return - EINVAL ;
2009-07-08 04:04:49 +04:00
syspath_add ( udev_enumerate , udev_device_get_syspath ( udev_device ) ) ;
2008-10-02 13:54:33 +04:00
udev_device_unref ( udev_device ) ;
2008-09-30 15:42:26 +04:00
return 0 ;
2008-09-29 00:18:40 +04:00
}
2008-08-28 00:02:41 +04:00
/**
2008-09-29 04:00:17 +04:00
* udev_enumerate_scan_devices :
* @ udev_enumerate : udev enumeration context
2008-08-28 00:02:41 +04:00
*
2009-06-15 22:04:46 +04:00
* Returns : 0 on success , otherwise a negative error value .
2008-08-28 00:02:41 +04:00
* */
2008-09-30 15:42:26 +04:00
int udev_enumerate_scan_devices ( struct udev_enumerate * udev_enumerate )
2008-08-28 00:02:41 +04:00
{
2008-09-29 04:00:17 +04:00
struct udev * udev = udev_enumerate_get_udev ( udev_enumerate ) ;
2008-09-10 20:00:31 +04:00
char base [ UTIL_PATH_SIZE ] ;
2008-08-28 00:02:41 +04:00
struct stat statbuf ;
2008-09-25 15:20:27 +04:00
if ( udev_enumerate = = NULL )
2008-09-29 04:00:17 +04:00
return - EINVAL ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( base , sizeof ( base ) , udev_get_sys_path ( udev ) , " /subsystem " , NULL ) ;
2008-08-28 00:02:41 +04:00
if ( stat ( base , & statbuf ) = = 0 ) {
2008-09-29 01:17:29 +04:00
/* we have /subsystem/, forget all the old stuff */
2008-11-01 22:16:24 +03:00
dbg ( udev , " searching '/subsystem/*/devices/*' dir \n " ) ;
2008-09-30 15:42:26 +04:00
scan_dir ( udev_enumerate , " subsystem " , " devices " , NULL ) ;
2008-08-28 00:02:41 +04:00
} else {
2008-11-01 22:16:24 +03:00
dbg ( udev , " searching '/bus/*/devices/*' dir \n " ) ;
2008-09-30 15:42:26 +04:00
scan_dir ( udev_enumerate , " bus " , " devices " , NULL ) ;
2008-11-01 22:16:24 +03:00
dbg ( udev , " searching '/class/*' dir \n " ) ;
2008-09-30 15:42:26 +04:00
scan_dir ( udev_enumerate , " class " , NULL , NULL ) ;
2008-08-28 00:02:41 +04:00
}
2008-09-29 04:00:17 +04:00
return 0 ;
2008-08-28 00:02:41 +04:00
}
2008-09-28 19:39:31 +04:00
2008-09-29 04:00:17 +04:00
/**
* udev_enumerate_scan_subsystems :
* @ udev_enumerate : udev enumeration context
*
2009-06-15 22:04:46 +04:00
* Returns : 0 on success , otherwise a negative error value .
2008-09-29 04:00:17 +04:00
* */
int udev_enumerate_scan_subsystems ( struct udev_enumerate * udev_enumerate )
2008-09-28 19:39:31 +04:00
{
2008-09-29 04:00:17 +04:00
struct udev * udev = udev_enumerate_get_udev ( udev_enumerate ) ;
2008-09-29 00:18:40 +04:00
char base [ UTIL_PATH_SIZE ] ;
struct stat statbuf ;
const char * subsysdir ;
if ( udev_enumerate = = NULL )
2008-09-29 04:00:17 +04:00
return - EINVAL ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( base , sizeof ( base ) , udev_get_sys_path ( udev ) , " /subsystem " , NULL ) ;
2008-09-29 00:18:40 +04:00
if ( stat ( base , & statbuf ) = = 0 )
2008-09-30 15:42:26 +04:00
subsysdir = " subsystem " ;
2008-09-29 00:18:40 +04:00
else
2008-09-30 15:42:26 +04:00
subsysdir = " bus " ;
if ( match_subsystem ( udev_enumerate , " subsystem " ) ) {
2008-11-01 22:16:24 +03:00
dbg ( udev , " searching '%s/*' dir \n " , subsysdir ) ;
2008-09-30 15:42:26 +04:00
scan_dir_and_add_devices ( udev_enumerate , subsysdir , NULL , NULL ) ;
}
2008-10-01 15:57:39 +04:00
if ( match_subsystem ( udev_enumerate , " drivers " ) ) {
2008-11-01 22:16:24 +03:00
dbg ( udev , " searching '%s/*/drivers/*' dir \n " , subsysdir ) ;
2008-10-01 15:57:39 +04:00
scan_dir ( udev_enumerate , subsysdir , " drivers " , " drivers " ) ;
}
2008-09-29 04:00:17 +04:00
return 0 ;
2008-09-28 19:39:31 +04:00
}