2001-09-28 19:42:25 +04:00
/*
2001-10-03 15:06:31 +04:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-09-28 19:42:25 +04:00
*
* This file is released under the GPL .
*/
# include "dev-cache.h"
# include "log.h"
# include "pool.h"
# include "hash.h"
# include <stdlib.h>
2001-10-03 15:06:31 +04:00
/*
* FIXME : really need to seperate names from the devices since
* multiple names can point to the same device .
*/
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
struct dev_iter {
struct hash_node * current ;
struct dev_filter * filter ;
} ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
struct dir_list {
struct list_head dir_list ;
char * dir [ 0 ] ;
2001-09-28 19:42:25 +04:00
} ;
2001-10-03 15:06:31 +04:00
static struct {
struct pool * mem ;
2001-09-28 19:42:25 +04:00
struct hash_table * devices ;
2001-10-03 15:06:31 +04:00
int has_scanned ;
struct list_head dirs ;
2001-09-28 19:42:25 +04:00
} _cache ;
2001-10-03 15:06:31 +04:00
# define _alloc(x) pool_alloc(_cache.mem, (x))
# define _free(x) pool_free(_cache.mem, (x))
/*
* return a new path for the destination of the path .
*/
static char * _follow_link ( const char * path , struct stat * info )
{
char buffer [ PATH_MAX + 1 ] , * r ;
int n ;
n = readlink ( path , buffer ) ;
if ( n < = 0 )
return NULL ;
buffer [ n ] = ' \0 ' ;
if ( stat ( buffer , info ) < 0 ) {
log_sys_err ( " stat " ) ;
return NULL ;
}
return pool_strdup ( _cache . mem , buffer ) ;
}
/*
* Get rid of extra slashes in the path string .
*/
static void _collapse_slashes ( char * str )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
char * ptr ;
int was_slash = 0 ;
for ( ptr = str ; * ptr ; ptr + + ) {
if ( * ptr = = ' / ' ) {
if ( was_slash )
continue ;
was_slash = 1 ;
} else
was_slash = 0 ;
* str + + = * ptr ;
}
* str = * ptr ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
static struct device * _create_dev ( const char * path )
2001-09-28 19:42:25 +04:00
{
struct stat info ;
2001-10-03 15:06:31 +04:00
struct device * dev ;
char * normed = _collapse_slashes ( path ) ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
if ( ! normed ) {
stack ;
return NULL ;
}
if ( stat ( normed , & info ) < 0 ) {
2001-09-28 19:42:25 +04:00
log_sys_error ( " stat " ) ;
2001-10-03 15:06:31 +04:00
return NULL ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
if ( S_ISLNK ( info . st_mode ) ) {
char * new_path ;
log_debug ( " %s is a symbolic link, following \n " , normed ) ;
normed = _follow_link ( normed , & info ) ;
if ( ! normed )
return NULL ;
}
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
if ( ! S_ISBLK ( info . st_mode ) ) {
log_debug ( " %s is not a block device \n " , normed ) ;
return NULL ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
if ( ! ( dev = _alloc ( sizeof ( * dev ) ) ) ) {
stack ;
return NULL ;
}
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
dev - > name = normed ;
dev - > dev = info . st_rdev ;
return dev ;
}
static struct device * _add ( const char * dir , const char * path )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
struct device * d ;
int len = strlen ( dir ) + strlen ( path ) + 2 ;
char * buffer = _alloc ( len ) ;
snprintf ( buffer , len , " %s/%s " , path ) ;
d = dev_cache_get ( path ) ;
if ( ! d )
_free ( buffer ) ; /* pool_free is safe in this case */
return d ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
static int _dir_scan ( const char * dir )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
int n , dirent_count ;
struct dirent * * dirent ;
dirent_count = scandir ( dir , & dirent , NULL , alphasort ) ;
if ( dirent_count > 0 ) {
for ( n = 0 ; n < dirent_count ; n + + ) {
_add ( dir , dirent [ n ] - > d_name ) ;
free ( dirent [ n ] ) ;
}
free ( dirent ) ;
}
return 1 ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
static void _full_scan ( void )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
struct dir_list * dl ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
if ( _cache . has_scanned )
return ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
for ( dl = _cache . dirs . next ; dl ! = & _cache . dirs ; dl = dl - > next )
_dir_scan ( dl . dir ) ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
_cache . has_scanned = 1 ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
int dev_cache_init ( void )
2001-09-28 19:42:25 +04:00
{
if ( ! ( _cache . mem = pool_create ( 10 * 1024 ) ) ) {
stack ;
return 0 ;
}
if ( ! ( _cache . devices = hash_create ( 128 ) ) ) {
stack ;
pool_destroy ( _cache . mem ) ;
_cache . mem = 0 ;
return 0 ;
}
return 1 ;
}
2001-10-03 15:06:31 +04:00
void dev_cache_exit ( void )
2001-09-28 19:42:25 +04:00
{
pool_destroy ( _cache . mem ) ;
hash_destroy ( _cache . devices ) ;
}
2001-10-03 15:06:31 +04:00
int dev_cache_add_dir ( const char * path )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
struct dir_list * dl ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
if ( ! ( dl = _alloc ( sizeof ( * dl ) + strlen ( path ) + 1 ) ) )
return 0 ;
strcpy ( dl - > dir , path ) ;
list_add ( dl , _cache . directories ) ;
return 1 ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
struct device * dev_cache_get ( const char * name )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
struct device * d = hash_lookup ( _cache . devices , name ) ;
if ( ! d & & ( d = _create_device ( name ) ) )
hash_insert ( t , name , d ) ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
return d ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
struct dev_iter * dev_iter_create ( struct dev_filter * f )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
struct dev_iter * di = dbg_malloc ( sizeof ( * di ) ) ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
if ( ! di )
return NULL ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
_full_scan ( ) ;
di - > current = hash_get_first ( ) ;
di - > filter = f ;
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
return di ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
void dev_iter_destroy ( struct dev_iter * iter )
2001-09-28 19:42:25 +04:00
{
2001-10-03 15:06:31 +04:00
dbg_free ( iter ) ;
}
2001-09-28 19:42:25 +04:00
2001-10-03 15:06:31 +04:00
static inline struct device * _iter_next ( struct dev_iter * iter )
{
struct device * d = hash_get_data ( _cache . devices , iter - > current ) ;
iter - > current = hash_next ( _cache . devices , iter - > current ) ;
return d ;
}
struct device * dev_iter_get ( struct dev_iter * iter )
{
while ( iter - > current ) {
struct device * d = _iter_next ( iter ) ;
if ( ! iter - > filter | |
iter - > filter - > pass_filter ( iter - > filter , d ) )
return d ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00
return NULL ;
2001-09-28 19:42:25 +04:00
}
2001-10-03 15:06:31 +04:00