2003-10-17 12:40:02 +04:00
/*
* Copyright ( C ) 2003 Greg Kroah - Hartman < greg @ kroah . com >
2008-09-10 04:40:42 +04:00
* Copyright ( C ) 2004 - 2008 Kay Sievers < kay . sievers @ vrfy . org >
2003-10-17 12:40:02 +04:00
*
2008-09-10 04:40:42 +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 , either version 2 of the License , or
* ( at your option ) any later version .
2003-10-17 12:40:02 +04:00
*
2008-09-10 04:40:42 +04:00
* 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 , see < http : //www.gnu.org/licenses/>.
2003-10-17 12:40:02 +04: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"
2004-11-06 16:28:01 +03:00
2008-09-06 17:45:31 +04:00
static size_t devpath_to_db_path ( struct udev * udev , const char * devpath , char * filename , size_t len )
2004-11-06 16:28:01 +03:00
{
2007-03-14 23:41:33 +03:00
size_t start ;
2005-08-27 04:59:20 +04:00
2008-03-29 18:12:41 +03:00
/* translate to location of db file */
2008-09-10 20:59:42 +04:00
util_strlcpy ( filename , udev_get_dev_path ( udev ) , len ) ;
start = util_strlcat ( filename , " /.udev/db/ " , len ) ;
util_strlcat ( filename , devpath , len ) ;
2008-09-10 20:39:23 +04:00
return util_path_encode ( & filename [ start ] , len - start ) ;
2004-11-06 16:28:01 +03:00
}
2003-10-18 10:32:17 +04:00
2007-03-15 04:09:39 +03:00
/* reverse mapping from the device file name to the devpath */
2008-09-06 17:45:31 +04:00
static int name_index ( struct udev * udev , const char * devpath , const char * name , int add )
2007-03-15 04:09:39 +03:00
{
char device [ PATH_SIZE ] ;
char filename [ PATH_SIZE * 2 ] ;
size_t start ;
int fd ;
/* directory with device name */
2008-09-10 20:59:42 +04:00
util_strlcpy ( filename , udev_get_dev_path ( udev ) , sizeof ( filename ) ) ;
start = util_strlcat ( filename , " /.udev/names/ " , sizeof ( filename ) ) ;
util_strlcat ( filename , name , sizeof ( filename ) ) ;
2008-09-10 20:39:23 +04:00
util_path_encode ( & filename [ start ] , sizeof ( filename ) - start ) ;
2007-03-15 04:09:39 +03:00
/* entry with the devpath */
2008-09-10 20:59:42 +04:00
util_strlcpy ( device , devpath , sizeof ( device ) ) ;
2008-09-10 20:39:23 +04:00
util_path_encode ( device , sizeof ( device ) ) ;
2008-09-10 20:59:42 +04:00
util_strlcat ( filename , " / " , sizeof ( filename ) ) ;
util_strlcat ( filename , device , sizeof ( filename ) ) ;
2007-03-15 04:09:39 +03:00
if ( add ) {
2008-09-06 17:45:31 +04:00
info ( udev , " creating index: '%s' \n " , filename ) ;
create_path ( udev , filename ) ;
2007-03-15 04:09:39 +03:00
fd = open ( filename , O_WRONLY | O_TRUNC | O_CREAT , 0644 ) ;
if ( fd > 0 )
close ( fd ) ;
} else {
2008-09-06 17:45:31 +04:00
info ( udev , " removing index: '%s' \n " , filename ) ;
2007-03-15 04:09:39 +03:00
unlink ( filename ) ;
2008-09-06 17:45:31 +04:00
delete_path ( udev , filename ) ;
2007-03-15 04:09:39 +03:00
}
return 0 ;
}
2008-09-06 17:45:31 +04:00
int udev_db_get_devices_by_name ( struct udev * udev , const char * name , struct list_head * name_list )
2007-03-17 12:08:25 +03:00
{
char dirname [ PATH_MAX ] ;
size_t start ;
DIR * dir ;
int rc = 0 ;
2008-09-10 20:59:42 +04:00
util_strlcpy ( dirname , udev_get_dev_path ( udev ) , sizeof ( dirname ) ) ;
start = util_strlcat ( dirname , " /.udev/names/ " , sizeof ( dirname ) ) ;
util_strlcat ( dirname , name , sizeof ( dirname ) ) ;
2008-09-10 20:39:23 +04:00
util_path_encode ( & dirname [ start ] , sizeof ( dirname ) - start ) ;
2007-03-17 12:08:25 +03:00
dir = opendir ( dirname ) ;
if ( dir = = NULL ) {
2008-09-06 17:45:31 +04:00
info ( udev , " no index directory '%s': %s \n " , dirname , strerror ( errno ) ) ;
2007-03-17 12:08:25 +03:00
rc = - 1 ;
goto out ;
}
2008-09-06 17:45:31 +04:00
info ( udev , " found index directory '%s' \n " , dirname ) ;
2007-03-17 12:08:25 +03:00
while ( 1 ) {
struct dirent * ent ;
char device [ PATH_SIZE ] ;
ent = readdir ( dir ) ;
if ( ent = = NULL | | ent - > d_name [ 0 ] = = ' \0 ' )
break ;
if ( ent - > d_name [ 0 ] = = ' . ' )
continue ;
2008-09-10 20:59:42 +04:00
util_strlcpy ( device , ent - > d_name , sizeof ( device ) ) ;
2008-09-10 20:39:23 +04:00
util_path_decode ( device ) ;
2008-09-06 17:45:31 +04:00
name_list_add ( udev , name_list , device , 0 ) ;
2007-03-17 12:08:25 +03:00
rc + + ;
}
closedir ( dir ) ;
out :
return rc ;
}
2008-09-06 17:45:31 +04:00
int udev_db_rename ( struct udev * udev , const char * devpath_old , const char * devpath )
2007-08-26 07:22:35 +04:00
{
char filename [ PATH_SIZE ] ;
char filename_old [ PATH_SIZE ] ;
2008-09-06 17:45:31 +04:00
devpath_to_db_path ( udev , devpath_old , filename_old , sizeof ( filename_old ) ) ;
devpath_to_db_path ( udev , devpath , filename , sizeof ( filename ) ) ;
2007-08-26 07:22:35 +04:00
return rename ( filename_old , filename ) ;
}
2008-09-06 17:45:31 +04:00
int udev_db_add_device ( struct udevice * udevice )
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
2008-09-06 17:45:31 +04:00
if ( udevice - > test_run )
2004-10-19 06:28:39 +04:00
return 0 ;
2008-09-06 17:45:31 +04:00
devpath_to_db_path ( udevice - > udev , udevice - > dev - > devpath , filename , sizeof ( filename ) ) ;
create_path ( udevice - > udev , filename ) ;
2007-03-16 19:24:39 +03:00
unlink ( filename ) ;
2006-08-18 04:27:16 +04:00
/*
2007-03-16 19:24:39 +03:00
* don ' t waste tmpfs memory pages , if we don ' t have any data to store
* create fake db - file ; store the node - name in a symlink target
2005-07-06 00:40:42 +04:00
*/
2008-09-06 17:45:31 +04:00
if ( list_empty ( & udevice - > symlink_list ) & & list_empty ( & udevice - > env_list ) & &
! udevice - > partitions & & ! udevice - > ignore_remove ) {
2008-04-17 18:03:03 +04:00
int ret ;
2008-09-06 17:45:31 +04:00
dbg ( udevice - > udev , " nothing interesting to store, create symlink \n " ) ;
2008-09-10 02:46:17 +04:00
udev_selinux_setfscreatecon ( udevice - > udev , filename , S_IFLNK ) ;
2008-09-06 17:45:31 +04:00
ret = symlink ( udevice - > name , filename ) ;
2008-09-10 02:46:17 +04:00
udev_selinux_resetfscreatecon ( udevice - > udev ) ;
2008-04-17 18:03:03 +04:00
if ( ret ! = 0 ) {
2008-09-06 17:45:31 +04:00
err ( udevice - > udev , " unable to create db link '%s': %s \n " , filename , strerror ( errno ) ) ;
2006-08-18 04:27:16 +04:00
return - 1 ;
}
} else {
FILE * f ;
2007-03-16 19:24:39 +03:00
struct name_entry * name_loop ;
2006-08-18 04:27:16 +04:00
f = fopen ( filename , " w " ) ;
if ( f = = NULL ) {
2008-09-06 17:45:31 +04:00
err ( udevice - > udev , " unable to create db file '%s': %s \n " , filename , strerror ( errno ) ) ;
2006-08-18 04:27:16 +04:00
return - 1 ;
}
2008-09-06 17:45:31 +04:00
dbg ( udevice - > udev , " storing data for device '%s' in '%s' \n " , udevice - > dev - > devpath , filename ) ;
2006-08-18 04:27:16 +04:00
2008-09-06 17:45:31 +04:00
fprintf ( f , " N:%s \n " , udevice - > name ) ;
list_for_each_entry ( name_loop , & udevice - > symlink_list , node ) {
2006-08-18 04:27:16 +04:00
fprintf ( f , " S:%s \n " , name_loop - > name ) ;
2007-03-16 19:24:39 +03:00
/* add symlink-name to index */
2008-09-06 17:45:31 +04:00
name_index ( udevice - > udev , udevice - > dev - > devpath , name_loop - > name , 1 ) ;
2007-03-15 04:09:39 +03:00
}
2008-09-06 17:45:31 +04:00
fprintf ( f , " M:%u:%u \n " , major ( udevice - > devt ) , minor ( udevice - > devt ) ) ;
if ( udevice - > link_priority ! = 0 )
fprintf ( f , " L:%u \n " , udevice - > link_priority ) ;
if ( udevice - > event_timeout > = 0 )
fprintf ( f , " T:%u \n " , udevice - > event_timeout ) ;
if ( udevice - > partitions ! = 0 )
fprintf ( f , " A:%u \n " , udevice - > partitions ) ;
if ( udevice - > ignore_remove )
fprintf ( f , " R:%u \n " , udevice - > ignore_remove ) ;
list_for_each_entry ( name_loop , & udevice - > env_list , node )
2006-08-18 04:27:16 +04:00
fprintf ( f , " E:%s \n " , name_loop - > name ) ;
fclose ( f ) ;
2004-11-06 16:28:01 +03:00
}
2007-03-16 19:24:39 +03:00
/* add name to index */
2008-09-06 17:45:31 +04:00
name_index ( udevice - > udev , udevice - > dev - > devpath , udevice - > name , 1 ) ;
2007-03-16 19:24:39 +03:00
2004-11-06 16:28:01 +03:00
return 0 ;
2003-10-18 10:32:17 +04:00
}
2008-09-06 17:45:31 +04:00
int udev_db_get_device ( struct udevice * udevice , 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 ;
2008-09-06 17:45:31 +04:00
sysfs_device_set_values ( udevice - > udev , udevice - > dev , devpath , NULL , NULL ) ;
devpath_to_db_path ( udevice - > udev , devpath , filename , sizeof ( filename ) ) ;
2006-08-18 04:27:16 +04:00
if ( lstat ( filename , & stats ) ! = 0 ) {
2008-09-06 17:45:31 +04:00
info ( udevice - > udev , " no db file to read %s: %s \n " , 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 ;
2008-09-06 17:45:31 +04:00
info ( udevice - > udev , " found a symlink as db file \n " ) ;
2006-08-18 04:27:16 +04:00
target_len = readlink ( filename , target , sizeof ( target ) ) ;
if ( target_len > 0 )
target [ target_len ] = ' \0 ' ;
else {
2008-09-06 17:45:31 +04:00
info ( udevice - > udev , " error reading db link %s: %s \n " , filename , strerror ( errno ) ) ;
2006-08-18 04:27:16 +04:00
return - 1 ;
}
2008-09-06 17:45:31 +04:00
dbg ( udevice - > udev , " db link points to '%s' \n " , target ) ;
2008-09-10 20:59:42 +04:00
util_strlcpy ( udevice - > name , target , sizeof ( udevice - > name ) ) ;
2006-08-18 04:27:16 +04:00
return 0 ;
}
if ( file_map ( filename , & buf , & bufsize ) ! = 0 ) {
2008-09-06 17:45:31 +04:00
info ( udevice - > udev , " error reading db file %s: %s \n " , filename , strerror ( errno ) ) ;
2006-08-18 04:27:16 +04:00
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 ;
2008-04-21 22:22:56 +04:00
if ( count > sizeof ( line ) )
count = sizeof ( line ) ;
memcpy ( line , & bufline [ 2 ] , count - 2 ) ;
line [ count - 2 ] = ' \0 ' ;
2004-11-06 16:28:01 +03:00
switch ( bufline [ 0 ] ) {
case ' N ' :
2008-09-10 20:59:42 +04:00
util_strlcpy ( udevice - > name , line , sizeof ( udevice - > name ) ) ;
2004-11-06 16:28:01 +03:00
break ;
2005-02-18 05:30:03 +03:00
case ' M ' :
2006-08-24 12:25:34 +04:00
sscanf ( line , " %u:%u " , & maj , & min ) ;
2008-09-06 17:45:31 +04:00
udevice - > devt = makedev ( maj , min ) ;
2005-02-18 05:30:03 +03:00
break ;
2004-11-06 16:28:01 +03:00
case ' S ' :
2008-09-06 17:45:31 +04:00
name_list_add ( udevice - > udev , & udevice - > symlink_list , line , 0 ) ;
2004-11-06 16:28:01 +03:00
break ;
2007-03-16 17:16:08 +03:00
case ' L ' :
2008-09-06 17:45:31 +04:00
udevice - > link_priority = atoi ( line ) ;
2007-03-16 17:16:08 +03:00
break ;
2008-04-21 22:22:56 +04:00
case ' T ' :
2008-09-06 17:45:31 +04:00
udevice - > event_timeout = atoi ( line ) ;
2008-04-21 22:22:56 +04:00
break ;
2004-11-06 16:28:01 +03:00
case ' A ' :
2008-09-06 17:45:31 +04:00
udevice - > partitions = atoi ( line ) ;
2004-11-06 16:28:01 +03:00
break ;
2004-11-13 16:43:24 +03:00
case ' R ' :
2008-09-06 17:45:31 +04:00
udevice - > ignore_remove = atoi ( line ) ;
2004-11-13 16:43:24 +03:00
break ;
2005-06-26 20:55:24 +04:00
case ' E ' :
2008-09-06 17:45:31 +04:00
name_list_add ( udevice - > udev , & udevice - > env_list , line , 0 ) ;
2005-06-26 20:55:24 +04:00
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
2008-09-06 17:45:31 +04:00
if ( udevice - > name [ 0 ] = = ' \0 ' )
2004-11-06 16:28:01 +03:00
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
}
2008-09-06 17:45:31 +04:00
int udev_db_delete_device ( struct udevice * udevice )
2003-08-06 10:57:23 +04:00
{
2005-03-07 06:29:43 +03:00
char filename [ PATH_SIZE ] ;
2007-03-15 04:09:39 +03:00
struct name_entry * name_loop ;
2003-10-21 07:28:42 +04:00
2008-09-06 17:45:31 +04:00
if ( udevice - > test_run )
2007-03-21 13:55:26 +03:00
return 0 ;
2008-09-06 17:45:31 +04:00
devpath_to_db_path ( udevice - > udev , udevice - > dev - > devpath , filename , sizeof ( filename ) ) ;
2005-02-21 15:48:10 +03:00
unlink ( filename ) ;
2003-10-21 07:28:42 +04:00
2008-09-06 17:45:31 +04:00
name_index ( udevice - > udev , udevice - > dev - > devpath , udevice - > name , 0 ) ;
list_for_each_entry ( name_loop , & udevice - > symlink_list , node )
name_index ( udevice - > udev , udevice - > dev - > devpath , name_loop - > name , 0 ) ;
2007-03-15 04:09:39 +03:00
2005-02-21 15:48:10 +03:00
return 0 ;
2003-10-21 07:28:42 +04:00
}
2008-09-06 17:45:31 +04:00
int udev_db_get_all_entries ( struct udev * udev , 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 ;
2008-09-10 20:59:42 +04:00
util_strlcpy ( dbpath , udev_get_dev_path ( udev ) , sizeof ( dbpath ) ) ;
util_strlcat ( dbpath , " /.udev/db " , sizeof ( dbpath ) ) ;
2005-11-16 06:14:15 +03:00
dir = opendir ( dbpath ) ;
2005-02-25 09:40:14 +03:00
if ( dir = = NULL ) {
2008-09-06 17:45:31 +04:00
info ( udev , " no udev_db available '%s': %s \n " , 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 ;
2007-03-14 23:41:33 +03:00
char device [ PATH_SIZE ] ;
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 ;
2008-09-10 20:59:42 +04:00
util_strlcpy ( device , ent - > d_name , sizeof ( device ) ) ;
2008-09-10 20:39:23 +04:00
util_path_decode ( device ) ;
2008-09-06 17:45:31 +04:00
name_list_add ( udev , name_list , device , 1 ) ;
dbg ( udev , " added '%s' \n " , device ) ;
2005-02-25 09:40:14 +03:00
}
closedir ( dir ) ;
return 0 ;
}