2003-10-17 12:40:02 +04:00
/*
* Copyright ( C ) 2003 Greg Kroah - Hartman < greg @ kroah . com >
2005-02-21 15:48:10 +03:00
* Copyright ( C ) 2004 - 2005 Kay Sievers < kay . sievers @ vrfy . org >
2003-10-17 12:40:02 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License .
*
* This program 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
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
2006-08-28 02:29:11 +04:00
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2003-10-17 12:40:02 +04:00
*
*/
2004-11-06 16:28:01 +03:00
2003-08-06 10:57:23 +04:00
# include <stdlib.h>
# include <stdio.h>
2004-03-02 10:47:59 +03:00
# include <string.h>
2004-03-23 09:22:20 +03:00
# include <stddef.h>
2005-03-06 14:16:32 +03:00
# include <unistd.h>
2003-08-06 10:57:23 +04:00
# include <fcntl.h>
# include <string.h>
# include <errno.h>
2004-11-06 16:28:01 +03:00
# include <dirent.h>
2006-08-24 02:13:07 +04:00
# include <sys/stat.h>
# include <sys/types.h>
2003-08-06 10:57:23 +04:00
2003-10-16 10:50:13 +04:00
# include "udev.h"
2003-08-06 10:57:23 +04:00
2004-11-06 16:28:01 +03:00
2005-08-28 01:27:43 +04:00
static int devpath_to_db_path ( const char * devpath , char * filename , size_t len )
2004-11-06 16:28:01 +03:00
{
2005-08-27 04:59:20 +04:00
size_t start , end , i ;
2005-08-28 01:27:43 +04:00
/* add location of db files */
2005-11-16 06:14:15 +03:00
strlcpy ( filename , udev_root , len ) ;
2005-11-24 22:06:22 +03:00
start = strlcat ( filename , " / " DB_DIR , len ) ;
2005-08-27 04:59:20 +04:00
end = strlcat ( filename , devpath , len ) ;
if ( end > len )
end = len ;
2004-11-06 16:28:01 +03:00
/* replace '/' to transform path into a filename */
2005-08-27 04:59:20 +04:00
for ( i = start + 1 ; i < end ; i + + )
if ( filename [ i ] = = ' / ' )
filename [ i ] = PATH_TO_NAME_CHAR ;
2004-11-06 16:28:01 +03:00
return 0 ;
}
2003-10-18 10:32:17 +04:00
2005-08-28 01:27:43 +04:00
static int db_file_to_devpath ( const char * filename , char * devpath , size_t len )
{
size_t end , i ;
strlcpy ( devpath , " / " , len ) ;
end = strlcat ( devpath , filename , len ) ;
/* replace PATH_TO_NAME_CHAR to transform name into devpath */
for ( i = 1 ; i < end ; i + + )
if ( devpath [ i ] = = PATH_TO_NAME_CHAR )
devpath [ i ] = ' / ' ;
return 0 ;
}
2004-11-12 08:32:19 +03:00
int udev_db_add_device ( struct udevice * udev )
2003-10-18 10:32:17 +04:00
{
2005-03-07 06:29:43 +03:00
char filename [ PATH_SIZE ] ;
2003-10-18 10:32:17 +04:00
2004-10-19 06:28:39 +04:00
if ( udev - > test_run )
return 0 ;
2006-08-18 04:27:16 +04:00
devpath_to_db_path ( udev - > dev - > devpath , filename , sizeof ( filename ) ) ;
create_path ( filename ) ;
/*
* create only a symlink with the name as the target
* if we don ' t have any interesting data to remember
2005-07-06 00:40:42 +04:00
*/
2006-08-21 04:38:48 +04:00
if ( list_empty ( & udev - > symlink_list ) & & list_empty ( & udev - > env_list ) & &
2005-07-06 00:40:42 +04:00
! udev - > partitions & & ! udev - > ignore_remove ) {
2006-08-18 04:27:16 +04:00
dbg ( " nothing interesting to store, create symlink " ) ;
unlink ( filename ) ;
if ( symlink ( udev - > name , filename ) ! = 0 ) {
err ( " unable to create db link '%s': %s " , filename , strerror ( errno ) ) ;
return - 1 ;
}
} else {
struct name_entry * name_loop ;
FILE * f ;
f = fopen ( filename , " w " ) ;
if ( f = = NULL ) {
err ( " unable to create db file '%s': %s " , filename , strerror ( errno ) ) ;
return - 1 ;
}
dbg ( " storing data for device '%s' in '%s' " , udev - > dev - > devpath , filename ) ;
fprintf ( f , " N:%s \n " , udev - > name ) ;
list_for_each_entry ( name_loop , & udev - > symlink_list , node )
fprintf ( f , " S:%s \n " , name_loop - > name ) ;
fprintf ( f , " M:%u:%u \n " , major ( udev - > devt ) , minor ( udev - > devt ) ) ;
if ( udev - > partitions )
fprintf ( f , " A:%u \n " , udev - > partitions ) ;
if ( udev - > ignore_remove )
fprintf ( f , " R:%u \n " , udev - > ignore_remove ) ;
list_for_each_entry ( name_loop , & udev - > env_list , node )
fprintf ( f , " E:%s \n " , name_loop - > name ) ;
fclose ( f ) ;
2004-11-06 16:28:01 +03:00
}
return 0 ;
2003-10-18 10:32:17 +04:00
}
2005-08-28 01:27:43 +04:00
int udev_db_get_device ( struct udevice * udev , const char * devpath )
2003-08-06 10:57:23 +04:00
{
2006-08-18 04:27:16 +04:00
struct stat stats ;
2005-08-28 01:27:43 +04:00
char filename [ PATH_SIZE ] ;
2005-03-07 06:29:43 +03:00
char line [ PATH_SIZE ] ;
2006-08-24 12:25:34 +04:00
unsigned int maj , min ;
2004-11-06 16:28:01 +03:00
char * bufline ;
char * buf ;
size_t bufsize ;
size_t cur ;
size_t count ;
2006-08-18 04:27:16 +04:00
strlcpy ( udev - > dev - > devpath , devpath , sizeof ( udev - > dev - > devpath ) ) ;
2005-08-28 01:27:43 +04:00
devpath_to_db_path ( devpath , filename , sizeof ( filename ) ) ;
2006-08-18 04:27:16 +04:00
if ( lstat ( filename , & stats ) ! = 0 ) {
2005-11-07 20:52:03 +03:00
info ( " no db file to read %s: %s " , filename , strerror ( errno ) ) ;
2004-10-14 10:13:26 +04:00
return - 1 ;
2004-11-06 16:28:01 +03:00
}
2006-08-18 04:27:16 +04:00
if ( ( stats . st_mode & S_IFMT ) = = S_IFLNK ) {
char target [ NAME_SIZE ] ;
int target_len ;
info ( " found a symlink as db file " ) ;
target_len = readlink ( filename , target , sizeof ( target ) ) ;
if ( target_len > 0 )
target [ target_len ] = ' \0 ' ;
else {
info ( " error reading db link %s: %s " , filename , strerror ( errno ) ) ;
return - 1 ;
}
dbg ( " db link points to '%s' " , target ) ;
strlcpy ( udev - > name , target , sizeof ( udev - > name ) ) ;
return 0 ;
}
if ( file_map ( filename , & buf , & bufsize ) ! = 0 ) {
info ( " error reading db file %s: %s " , filename , strerror ( errno ) ) ;
return - 1 ;
}
2004-10-14 10:13:26 +04:00
2004-11-06 16:28:01 +03:00
cur = 0 ;
while ( cur < bufsize ) {
count = buf_get_line ( buf , bufsize , cur ) ;
bufline = & buf [ cur ] ;
cur + = count + 1 ;
switch ( bufline [ 0 ] ) {
case ' N ' :
2005-03-07 06:29:43 +03:00
if ( count > sizeof ( udev - > name ) )
2005-03-27 14:39:12 +04:00
count = sizeof ( udev - > name ) ;
2005-08-08 04:21:55 +04:00
memcpy ( udev - > name , & bufline [ 2 ] , count - 2 ) ;
udev - > name [ count - 2 ] = ' \0 ' ;
2004-11-06 16:28:01 +03:00
break ;
2005-02-18 05:30:03 +03:00
case ' M ' :
2005-03-07 06:29:43 +03:00
if ( count > sizeof ( line ) )
2005-03-27 14:39:12 +04:00
count = sizeof ( line ) ;
2005-08-08 04:21:55 +04:00
memcpy ( line , & bufline [ 2 ] , count - 2 ) ;
line [ count - 2 ] = ' \0 ' ;
2006-08-24 12:25:34 +04:00
sscanf ( line , " %u:%u " , & maj , & min ) ;
udev - > devt = makedev ( maj , min ) ;
2005-02-18 05:30:03 +03:00
break ;
2004-11-06 16:28:01 +03:00
case ' S ' :
2005-03-27 14:39:12 +04:00
if ( count > sizeof ( line ) )
count = sizeof ( line ) ;
2005-08-08 04:21:55 +04:00
memcpy ( line , & bufline [ 2 ] , count - 2 ) ;
line [ count - 2 ] = ' \0 ' ;
2005-03-07 06:29:43 +03:00
name_list_add ( & udev - > symlink_list , line , 0 ) ;
2004-11-06 16:28:01 +03:00
break ;
case ' A ' :
2005-03-27 14:39:12 +04:00
if ( count > sizeof ( line ) )
count = sizeof ( line ) ;
2005-08-08 04:21:55 +04:00
memcpy ( line , & bufline [ 2 ] , count - 2 ) ;
line [ count - 2 ] = ' \0 ' ;
2004-11-06 16:28:01 +03:00
udev - > partitions = atoi ( line ) ;
break ;
2004-11-13 16:43:24 +03:00
case ' R ' :
2005-03-27 14:39:12 +04:00
if ( count > sizeof ( line ) )
count = sizeof ( line ) ;
2005-08-08 04:21:55 +04:00
memcpy ( line , & bufline [ 2 ] , count - 2 ) ;
line [ count - 2 ] = ' \0 ' ;
2004-11-13 16:43:24 +03:00
udev - > ignore_remove = atoi ( line ) ;
break ;
2005-06-26 20:55:24 +04:00
case ' E ' :
if ( count > sizeof ( line ) )
count = sizeof ( line ) ;
2005-08-08 04:21:55 +04:00
memcpy ( line , & bufline [ 2 ] , count - 2 ) ;
line [ count - 2 ] = ' \0 ' ;
2005-06-26 20:55:24 +04:00
name_list_add ( & udev - > env_list , line , 0 ) ;
break ;
2004-11-06 16:28:01 +03:00
}
}
2005-03-05 04:33:31 +03:00
file_unmap ( buf , bufsize ) ;
2003-11-25 09:27:17 +03:00
2004-11-06 16:28:01 +03:00
if ( udev - > name [ 0 ] = = ' \0 ' )
return - 1 ;
2004-10-19 06:11:51 +04:00
2003-12-20 05:29:01 +03:00
return 0 ;
2003-08-06 10:57:23 +04:00
}
2005-02-21 15:48:10 +03:00
int udev_db_delete_device ( struct udevice * udev )
2003-08-06 10:57:23 +04:00
{
2005-03-07 06:29:43 +03:00
char filename [ PATH_SIZE ] ;
2003-10-21 07:28:42 +04:00
2006-01-09 23:18:00 +03:00
devpath_to_db_path ( udev - > dev - > devpath , filename , sizeof ( filename ) ) ;
2005-02-21 15:48:10 +03:00
unlink ( filename ) ;
2003-10-21 07:28:42 +04:00
2005-02-21 15:48:10 +03:00
return 0 ;
2003-10-21 07:28:42 +04:00
}
2005-08-28 01:27:43 +04:00
int udev_db_lookup_name ( const char * name , char * devpath , size_t len )
2003-12-31 09:31:37 +03:00
{
2005-11-16 06:14:15 +03:00
char dbpath [ PATH_MAX ] ;
2004-11-06 16:28:01 +03:00
DIR * dir ;
2005-08-27 00:43:49 +04:00
int found = 0 ;
2004-11-06 16:28:01 +03:00
2005-11-16 06:14:15 +03:00
strlcpy ( dbpath , udev_root , sizeof ( dbpath ) ) ;
2005-11-24 22:06:22 +03:00
strlcat ( dbpath , " / " DB_DIR , sizeof ( dbpath ) ) ;
2005-11-16 06:14:15 +03:00
dir = opendir ( dbpath ) ;
2004-11-06 16:28:01 +03:00
if ( dir = = NULL ) {
2005-12-20 13:23:08 +03:00
info ( " no udev_db available '%s': %s " , dbpath , strerror ( errno ) ) ;
2004-11-06 16:28:01 +03:00
return - 1 ;
2004-01-13 12:01:19 +03:00
}
2005-08-27 00:43:49 +04:00
while ( ! found ) {
2005-03-05 13:55:59 +03:00
struct dirent * ent ;
2005-03-07 06:29:43 +03:00
char filename [ PATH_SIZE ] ;
char nodename [ PATH_SIZE ] ;
2006-08-18 04:27:16 +04:00
struct stat stats ;
2005-03-05 07:35:31 +03:00
char * bufline ;
char * buf ;
size_t bufsize ;
size_t cur ;
size_t count ;
2004-11-06 16:28:01 +03:00
ent = readdir ( dir ) ;
if ( ent = = NULL | | ent - > d_name [ 0 ] = = ' \0 ' )
break ;
if ( ent - > d_name [ 0 ] = = ' . ' )
continue ;
2004-01-13 12:01:19 +03:00
2005-11-16 06:14:15 +03:00
snprintf ( filename , sizeof ( filename ) , " %s/%s " , dbpath , ent - > d_name ) ;
2005-03-07 06:29:43 +03:00
filename [ sizeof ( filename ) - 1 ] = ' \0 ' ;
2005-03-05 07:35:31 +03:00
dbg ( " looking at '%s' " , filename ) ;
2004-01-20 06:40:32 +03:00
2006-08-18 04:27:16 +04:00
if ( lstat ( filename , & stats ) ! = 0 ) {
info ( " unable to read %s: %s " , filename , strerror ( errno ) ) ;
continue ;
}
if ( ( stats . st_mode & S_IFMT ) = = S_IFLNK ) {
char target [ NAME_SIZE ] ;
int target_len ;
info ( " found a symlink as db file " ) ;
target_len = readlink ( filename , target , sizeof ( target ) ) ;
if ( target_len > 0 )
target [ target_len ] = ' \0 ' ;
else {
info ( " error reading db link %s: %s " , filename , strerror ( errno ) ) ;
return - 1 ;
}
dbg ( " db link points to '%s' " , target ) ;
if ( strcmp ( name , target ) = = 0 ) {
db_file_to_devpath ( ent - > d_name , devpath , len ) ;
found = 1 ;
}
continue ;
}
2005-03-05 07:35:31 +03:00
if ( file_map ( filename , & buf , & bufsize ) ! = 0 ) {
2006-08-18 04:27:16 +04:00
info ( " unable to read db file '%s': %s " , filename , strerror ( errno ) ) ;
2005-03-05 07:35:31 +03:00
continue ;
}
2004-01-20 06:40:32 +03:00
2005-03-05 07:35:31 +03:00
cur = 0 ;
2005-08-27 00:43:49 +04:00
while ( cur < bufsize & & ! found ) {
2005-03-05 07:35:31 +03:00
count = buf_get_line ( buf , bufsize , cur ) ;
bufline = & buf [ cur ] ;
cur + = count + 1 ;
switch ( bufline [ 0 ] ) {
case ' N ' :
case ' S ' :
2005-03-07 06:29:43 +03:00
if ( count > sizeof ( nodename ) )
2005-03-27 14:39:12 +04:00
count = sizeof ( nodename ) ;
2005-08-08 04:21:55 +04:00
memcpy ( nodename , & bufline [ 2 ] , count - 2 ) ;
nodename [ count - 2 ] = ' \0 ' ;
2005-03-05 07:35:31 +03:00
dbg ( " compare '%s' '%s' " , nodename , name ) ;
if ( strcmp ( nodename , name ) = = 0 ) {
2005-08-28 01:27:43 +04:00
db_file_to_devpath ( ent - > d_name , devpath , len ) ;
2005-08-27 00:43:49 +04:00
found = 1 ;
2005-03-05 07:35:31 +03:00
}
break ;
default :
continue ;
2004-11-06 16:28:01 +03:00
}
}
2005-03-05 07:35:31 +03:00
file_unmap ( buf , bufsize ) ;
2004-01-20 06:40:32 +03:00
}
2004-03-04 05:16:35 +03:00
2004-11-06 16:28:01 +03:00
closedir ( dir ) ;
2005-08-28 01:27:43 +04:00
if ( found )
2005-08-27 00:43:49 +04:00
return 0 ;
2005-08-28 01:27:43 +04:00
else
2005-08-27 00:43:49 +04:00
return - 1 ;
2004-01-20 06:40:32 +03:00
}
2005-02-25 09:40:14 +03:00
2005-08-27 04:59:20 +04:00
int udev_db_get_all_entries ( struct list_head * name_list )
2005-02-25 09:40:14 +03:00
{
2005-11-16 06:14:15 +03:00
char dbpath [ PATH_MAX ] ;
2005-02-25 09:40:14 +03:00
DIR * dir ;
2005-11-16 06:14:15 +03:00
strlcpy ( dbpath , udev_root , sizeof ( dbpath ) ) ;
2005-11-24 22:06:22 +03:00
strlcat ( dbpath , " / " DB_DIR , sizeof ( dbpath ) ) ;
2005-11-16 06:14:15 +03:00
dir = opendir ( dbpath ) ;
2005-02-25 09:40:14 +03:00
if ( dir = = NULL ) {
2005-12-20 13:23:08 +03:00
info ( " no udev_db available '%s': %s " , dbpath , strerror ( errno ) ) ;
2005-02-25 09:40:14 +03:00
return - 1 ;
}
while ( 1 ) {
2005-03-05 13:55:59 +03:00
struct dirent * ent ;
2005-08-27 04:59:20 +04:00
char filename [ PATH_SIZE ] = " / " ;
size_t end , i ;
2005-03-05 13:55:59 +03:00
2005-02-25 09:40:14 +03:00
ent = readdir ( dir ) ;
if ( ent = = NULL | | ent - > d_name [ 0 ] = = ' \0 ' )
break ;
if ( ent - > d_name [ 0 ] = = ' . ' )
continue ;
2005-08-27 04:59:20 +04:00
end = strlcat ( filename , ent - > d_name , sizeof ( filename ) ) ;
for ( i = 1 ; i < end ; i + + )
if ( filename [ i ] = = PATH_TO_NAME_CHAR )
filename [ i ] = ' / ' ;
name_list_add ( name_list , filename , 1 ) ;
dbg ( " added '%s' " , filename ) ;
2005-02-25 09:40:14 +03:00
}
closedir ( dir ) ;
return 0 ;
}