2008-08-28 00:02:41 +04:00
/*
* libudev - interface to udev device information
*
* Copyright ( C ) 2008 Kay Sievers < kay . sievers @ vrfy . org >
*
* 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 .
*
* 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/>.
*/
# include <stdio.h>
# include <stdlib.h>
# include <stddef.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include <dirent.h>
2008-09-13 23:09:28 +04:00
# include <fcntl.h>
2008-08-28 00:02:41 +04:00
# include <sys/stat.h>
# include "libudev.h"
# include "libudev-private.h"
2008-09-01 20:52:22 +04:00
struct udev_device {
int refcount ;
struct udev * udev ;
2008-09-12 02:58:40 +04:00
struct udev_device * parent_device ;
2008-09-01 20:52:22 +04:00
char * syspath ;
2008-09-11 19:08:12 +04:00
const char * devpath ;
const char * sysname ;
2008-09-26 21:43:32 +04:00
char * devnode ;
2008-09-01 20:52:22 +04:00
char * subsystem ;
2008-09-26 21:44:53 +04:00
struct list_node devlink_list ;
struct list_node properties_list ;
2008-09-09 16:06:20 +04:00
char * action ;
2008-09-26 21:43:32 +04:00
int event_timeout ;
2008-09-09 16:06:20 +04:00
char * driver ;
char * devpath_old ;
char * physdevpath ;
int timeout ;
dev_t devnum ;
2008-09-10 12:09:34 +04:00
unsigned long long int seqnum ;
int num_fake_partitions ;
2008-09-10 16:17:36 +04:00
int devlink_priority ;
2008-09-10 12:09:34 +04:00
int ignore_remove ;
2008-09-26 21:44:53 +04:00
struct list_node attr_list ;
2008-09-26 21:43:32 +04:00
int info_loaded ;
2008-09-01 20:52:22 +04:00
} ;
2008-09-16 04:12:47 +04:00
static size_t syspath_to_db_path ( struct udev_device * udev_device , char * filename , size_t len )
2008-09-10 16:17:36 +04:00
{
size_t start ;
/* translate to location of db file */
2008-09-16 04:12:47 +04:00
util_strlcpy ( filename , udev_get_dev_path ( udev_device - > udev ) , len ) ;
2008-09-10 20:00:31 +04:00
start = util_strlcat ( filename , " /.udev/db/ " , len ) ;
2008-09-16 04:12:47 +04:00
util_strlcat ( filename , udev_device - > devpath , len ) ;
2008-09-10 19:08:24 +04:00
return util_path_encode ( & filename [ start ] , len - start ) ;
2008-09-10 16:17:36 +04:00
}
static int device_read_db ( struct udev_device * udev_device )
{
struct stat stats ;
2008-09-10 20:00:31 +04:00
char filename [ UTIL_PATH_SIZE ] ;
char line [ UTIL_LINE_SIZE ] ;
2008-09-10 16:17:36 +04:00
FILE * f ;
2008-09-16 04:12:47 +04:00
syspath_to_db_path ( udev_device , filename , sizeof ( filename ) ) ;
2008-09-10 16:17:36 +04:00
if ( lstat ( filename , & stats ) ! = 0 ) {
info ( udev_device - > udev , " no db file to read %s: %s \n " , filename , strerror ( errno ) ) ;
return - 1 ;
}
if ( ( stats . st_mode & S_IFMT ) = = S_IFLNK ) {
2008-09-10 20:00:31 +04:00
char target [ UTIL_PATH_SIZE ] ;
2008-09-10 16:17:36 +04:00
int target_len ;
target_len = readlink ( filename , target , sizeof ( target ) ) ;
if ( target_len > 0 )
target [ target_len ] = ' \0 ' ;
else {
info ( udev_device - > udev , " error reading db link %s: %s \n " , filename , strerror ( errno ) ) ;
return - 1 ;
}
2008-09-26 21:43:32 +04:00
if ( asprintf ( & udev_device - > devnode , " %s/%s " , udev_get_dev_path ( udev_device - > udev ) , target ) < 0 )
2008-09-10 16:17:36 +04:00
return - ENOMEM ;
2008-09-26 21:43:32 +04:00
info ( udev_device - > udev , " device %p filled with db symlink data '%s' \n " , udev_device , udev_device - > devnode ) ;
2008-09-10 16:17:36 +04:00
return 0 ;
}
f = fopen ( filename , " r " ) ;
if ( f = = NULL ) {
info ( udev_device - > udev , " error reading db file %s: %s \n " , filename , strerror ( errno ) ) ;
return - 1 ;
}
while ( fgets ( line , sizeof ( line ) , f ) ) {
ssize_t len ;
const char * val ;
len = strlen ( line ) ;
if ( len < 4 )
break ;
line [ len - 1 ] = ' \0 ' ;
val = & line [ 2 ] ;
switch ( line [ 0 ] ) {
case ' N ' :
2008-09-26 21:43:32 +04:00
asprintf ( & udev_device - > devnode , " %s/%s " , udev_get_dev_path ( udev_device - > udev ) , val ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' S ' :
2008-09-10 20:00:31 +04:00
util_strlcpy ( filename , udev_get_dev_path ( udev_device - > udev ) , sizeof ( filename ) ) ;
util_strlcat ( filename , " / " , sizeof ( filename ) ) ;
util_strlcat ( filename , val , sizeof ( filename ) ) ;
2008-09-10 16:17:36 +04:00
device_add_devlink ( udev_device , filename ) ;
break ;
case ' L ' :
device_set_devlink_priority ( udev_device , atoi ( val ) ) ;
break ;
case ' T ' :
2008-09-26 21:43:32 +04:00
device_set_event_timeout ( udev_device , atoi ( val ) ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' A ' :
device_set_num_fake_partitions ( udev_device , atoi ( val ) ) ;
break ;
case ' R ' :
device_set_ignore_remove ( udev_device , atoi ( val ) ) ;
break ;
case ' E ' :
2008-09-15 22:19:56 +04:00
device_add_property_from_string ( udev_device , val ) ;
2008-09-10 16:17:36 +04:00
break ;
}
}
fclose ( f ) ;
2008-09-26 21:41:50 +04:00
info ( udev_device - > udev , " device %p filled with db file data \n " , udev_device ) ;
2008-09-26 01:26:22 +04:00
return 0 ;
2008-09-10 16:17:36 +04:00
}
2008-09-26 21:43:32 +04:00
static int device_read_uevent_file ( struct udev_device * udev_device )
{
char filename [ UTIL_PATH_SIZE ] ;
FILE * f ;
char line [ UTIL_LINE_SIZE ] ;
int maj = 0 ;
int min = 0 ;
util_strlcpy ( filename , udev_device - > syspath , sizeof ( filename ) ) ;
util_strlcat ( filename , " /uevent " , sizeof ( filename ) ) ;
f = fopen ( filename , " r " ) ;
if ( f = = NULL )
return - 1 ;
while ( fgets ( line , sizeof ( line ) , f ) ) {
char * pos ;
pos = strchr ( line , ' \n ' ) ;
if ( pos = = NULL )
continue ;
pos [ 0 ] = ' \0 ' ;
if ( strncmp ( line , " MAJOR= " , 6 ) = = 0 )
maj = strtoull ( & line [ 6 ] , NULL , 10 ) ;
else if ( strncmp ( line , " MINOR= " , 6 ) = = 0 )
min = strtoull ( & line [ 6 ] , NULL , 10 ) ;
device_add_property_from_string ( udev_device , line ) ;
}
udev_device - > devnum = makedev ( maj , min ) ;
fclose ( f ) ;
return 0 ;
}
static void device_load_info ( struct udev_device * device )
{
device_read_uevent_file ( device ) ;
device_read_db ( device ) ;
device - > info_loaded = 1 ;
}
void device_set_info_loaded ( struct udev_device * device )
{
device - > info_loaded = 1 ;
}
2008-08-29 01:05:01 +04:00
struct udev_device * device_init ( struct udev * udev )
2008-08-28 00:02:41 +04:00
{
struct udev_device * udev_device ;
2008-08-29 01:05:01 +04:00
if ( udev = = NULL )
return NULL ;
2008-08-28 00:02:41 +04:00
udev_device = malloc ( sizeof ( struct udev_device ) ) ;
if ( udev_device = = NULL )
return NULL ;
memset ( udev_device , 0x00 , sizeof ( struct udev_device ) ) ;
udev_device - > refcount = 1 ;
udev_device - > udev = udev ;
2008-09-26 21:44:53 +04:00
list_init ( & udev_device - > devlink_list ) ;
list_init ( & udev_device - > properties_list ) ;
list_init ( & udev_device - > attr_list ) ;
2008-09-06 17:45:31 +04:00
info ( udev_device - > udev , " udev_device: %p created \n " , udev_device ) ;
2008-08-28 00:02:41 +04:00
return udev_device ;
}
/**
2008-09-16 04:12:47 +04:00
* udev_device_new_from_syspath :
2008-08-28 00:02:41 +04:00
* @ udev : udev library context
2008-09-16 04:12:47 +04:00
* @ syspath : sys device path including sys directory
2008-08-28 00:02:41 +04:00
*
2008-09-16 04:12:47 +04:00
* Create new udev device , and fill in information from the sys
* device and the udev database entry . The sypath is the absolute
* path to the device , including the sys mount point .
2008-08-28 00:02:41 +04:00
*
* The initial refcount is 1 , and needs to be decremented to
* release the ressources of the udev device .
*
* Returns : a new udev device , or # NULL , if it does not exist
* */
2008-09-16 04:12:47 +04:00
struct udev_device * udev_device_new_from_syspath ( struct udev * udev , const char * syspath )
2008-08-28 00:02:41 +04:00
{
2008-09-28 05:34:57 +04:00
size_t len ;
const char * subdir ;
const char * pos ;
2008-09-10 20:00:31 +04:00
char path [ UTIL_PATH_SIZE ] ;
2008-08-28 00:02:41 +04:00
struct stat statbuf ;
struct udev_device * udev_device ;
2008-08-29 01:05:01 +04:00
if ( udev = = NULL )
return NULL ;
2008-09-16 04:12:47 +04:00
if ( syspath = = NULL )
2008-08-29 01:05:01 +04:00
return NULL ;
2008-09-28 05:34:57 +04:00
/* path starts in sys */
len = strlen ( udev_get_sys_path ( udev ) ) ;
if ( strncmp ( syspath , udev_get_sys_path ( udev ) , len ) ! = 0 ) {
info ( udev , " not in sys :%s \n " , syspath ) ;
2008-08-28 00:02:41 +04:00
return NULL ;
2008-09-11 19:08:12 +04:00
}
2008-08-28 00:02:41 +04:00
2008-09-28 05:34:57 +04:00
/* path is not a root directory */
subdir = & syspath [ len + 1 ] ;
pos = strrchr ( subdir , ' / ' ) ;
if ( pos = = NULL | | pos < & subdir [ 2 ] ) {
2008-09-28 19:39:31 +04:00
info ( udev , " not a subdir :%s \n " , syspath ) ;
2008-08-28 00:02:41 +04:00
return NULL ;
2008-09-28 05:34:57 +04:00
}
2008-08-28 00:02:41 +04:00
2008-08-29 01:05:01 +04:00
/* resolve possible symlink to real path */
2008-09-16 04:12:47 +04:00
util_strlcpy ( path , syspath , sizeof ( path ) ) ;
2008-09-10 16:29:07 +04:00
util_resolve_sys_link ( udev , path , sizeof ( path ) ) ;
2008-09-28 05:34:57 +04:00
/* path exists in sys */
if ( strncmp ( & syspath [ len ] , " /devices/ " , 9 ) = = 0 | |
strncmp ( & syspath [ len ] , " /class/ " , 7 ) = = 0 | |
strncmp ( & syspath [ len ] , " /block/ " , 7 ) = = 0 ) {
char file [ UTIL_PATH_SIZE ] ;
/* all "devices" require a "uevent" file */
util_strlcpy ( file , path , sizeof ( file ) ) ;
util_strlcat ( file , " /uevent " , sizeof ( file ) ) ;
if ( stat ( file , & statbuf ) ! = 0 ) {
info ( udev , " not a device: %s \n " , syspath ) ;
return NULL ;
}
} else {
/* everything else just needs to be a directory */
if ( stat ( path , & statbuf ) ! = 0 | | ! S_ISDIR ( statbuf . st_mode ) ) {
info ( udev , " directory not found: %s \n " , syspath ) ;
return NULL ;
}
}
udev_device = device_init ( udev ) ;
if ( udev_device = = NULL )
return NULL ;
2008-09-16 04:12:47 +04:00
device_set_syspath ( udev_device , path ) ;
2008-09-06 17:45:31 +04:00
info ( udev , " device %p has devpath '%s' \n " , udev_device , udev_device_get_devpath ( udev_device ) ) ;
2008-08-28 00:02:41 +04:00
return udev_device ;
}
2008-09-22 10:28:56 +04:00
struct udev_device * udev_device_new_from_devnum ( struct udev * udev , char type , dev_t devnum )
{
char path [ UTIL_PATH_SIZE ] ;
2008-09-24 23:25:31 +04:00
const char * type_str ;
2008-09-29 04:00:17 +04:00
struct udev_enumerate * udev_enumerate ;
2008-09-28 03:34:55 +04:00
struct udev_list_entry * list_entry ;
2008-09-25 15:20:27 +04:00
struct udev_device * device = NULL ;
2008-09-24 23:25:31 +04:00
if ( type = = ' b ' )
type_str = " block " ;
else if ( type = = ' c ' )
type_str = " char " ;
else
return NULL ;
2008-09-22 10:28:56 +04:00
2008-09-28 05:34:57 +04:00
/* /sys/dev/{block,char}/<maj>:<min> link */
2008-09-24 23:25:31 +04:00
snprintf ( path , sizeof ( path ) , " %s/dev/%s/%u:%u " , udev_get_sys_path ( udev ) ,
type_str , major ( devnum ) , minor ( devnum ) ) ;
2008-09-25 15:20:27 +04:00
if ( util_resolve_sys_link ( udev , path , sizeof ( path ) ) = = 0 )
return udev_device_new_from_syspath ( udev , path ) ;
2008-09-22 10:28:56 +04:00
2008-09-29 04:00:17 +04:00
udev_enumerate = udev_enumerate_new ( udev ) ;
if ( udev_enumerate = = NULL )
return NULL ;
2008-09-28 19:39:31 +04:00
/* fallback to search sys devices for the major/minor */
if ( type = = ' b ' )
2008-09-29 04:00:17 +04:00
udev_enumerate_scan_devices ( udev_enumerate , " block " , NULL ) ;
2008-09-28 19:39:31 +04:00
else if ( type = = ' c ' )
2008-09-29 04:00:17 +04:00
udev_enumerate_scan_devices ( udev_enumerate , " !block " , NULL ) ;
udev_list_entry_foreach ( list_entry , udev_enumerate_get_list_entry ( udev_enumerate ) ) {
2008-09-25 15:20:27 +04:00
struct udev_device * device_loop ;
2008-09-28 03:34:55 +04:00
device_loop = udev_device_new_from_syspath ( udev , udev_list_entry_get_name ( list_entry ) ) ;
2008-09-25 15:20:27 +04:00
if ( device_loop ! = NULL ) {
if ( udev_device_get_devnum ( device_loop ) = = devnum ) {
2008-09-28 19:39:31 +04:00
const char * subsystem ;
subsystem = udev_device_get_subsystem ( device_loop ) ;
if ( type = = ' b ' & & strcmp ( subsystem , " block " ) ! = 0 )
continue ;
if ( type = = ' c ' & & strcmp ( subsystem , " block " ) = = 0 )
continue ;
2008-09-25 15:20:27 +04:00
device = device_loop ;
break ;
}
udev_device_unref ( device_loop ) ;
}
}
2008-09-29 04:00:17 +04:00
udev_enumerate_unref ( udev_enumerate ) ;
2008-09-25 15:20:27 +04:00
return device ;
2008-09-22 10:28:56 +04:00
}
2008-09-12 02:58:40 +04:00
static struct udev_device * device_new_from_parent ( struct udev_device * udev_device )
2008-09-11 19:08:12 +04:00
{
struct udev_device * udev_device_parent = NULL ;
char path [ UTIL_PATH_SIZE ] ;
2008-09-28 05:34:57 +04:00
const char * subdir ;
2008-09-11 19:08:12 +04:00
2008-09-28 05:34:57 +04:00
/* follow "device" link in deprecated sys layout */
if ( strncmp ( udev_device - > devpath , " /class/ " , 7 ) = = 0 | |
strncmp ( udev_device - > devpath , " /block/ " , 7 ) = = 0 ) {
util_strlcpy ( path , udev_device - > syspath , sizeof ( path ) ) ;
util_strlcat ( path , " /device " , sizeof ( path ) ) ;
if ( util_resolve_sys_link ( udev_device - > udev , path , sizeof ( path ) ) = = 0 )
udev_device_parent = udev_device_new_from_syspath ( udev_device - > udev , path ) ;
return udev_device_parent ;
}
2008-09-11 19:08:12 +04:00
2008-09-16 04:12:47 +04:00
util_strlcpy ( path , udev_device - > syspath , sizeof ( path ) ) ;
2008-09-28 05:34:57 +04:00
subdir = & path [ strlen ( udev_get_sys_path ( udev_device - > udev ) ) + 1 ] ;
2008-09-11 19:08:12 +04:00
while ( 1 ) {
2008-09-28 05:34:57 +04:00
char * pos ;
pos = strrchr ( subdir , ' / ' ) ;
if ( pos = = NULL | | pos < & subdir [ 2 ] )
2008-09-11 19:08:12 +04:00
break ;
pos [ 0 ] = ' \0 ' ;
2008-09-16 04:12:47 +04:00
udev_device_parent = udev_device_new_from_syspath ( udev_device - > udev , path ) ;
2008-09-11 19:08:12 +04:00
if ( udev_device_parent ! = NULL )
2008-09-15 22:19:56 +04:00
return udev_device_parent ;
}
return NULL ;
2008-09-11 19:08:12 +04:00
}
2008-09-12 02:58:40 +04:00
struct udev_device * udev_device_get_parent ( struct udev_device * udev_device )
{
2008-09-28 05:34:57 +04:00
if ( udev_device = = NULL )
return NULL ;
2008-09-15 22:19:56 +04:00
if ( udev_device - > parent_device ! = NULL ) {
info ( udev_device - > udev , " returning existing parent %p \n " , udev_device - > parent_device ) ;
return udev_device - > parent_device ;
}
udev_device - > parent_device = device_new_from_parent ( udev_device ) ;
2008-09-12 02:58:40 +04:00
return udev_device - > parent_device ;
}
2008-08-28 00:02:41 +04:00
/**
* udev_device_get_udev :
2008-08-30 18:16:37 +04:00
* @ udev_device : udev device
2008-08-28 00:02:41 +04:00
*
* Retrieve the udev library context the device was created with .
*
* Returns : the udev library context
* */
struct udev * udev_device_get_udev ( struct udev_device * udev_device )
{
2008-08-29 01:05:01 +04:00
if ( udev_device = = NULL )
return NULL ;
2008-08-28 00:02:41 +04:00
return udev_device - > udev ;
}
/**
* udev_device_ref :
* @ udev_device : udev device
*
* Take a reference of a udev device .
*
* Returns : the passed udev device
* */
struct udev_device * udev_device_ref ( struct udev_device * udev_device )
{
2008-08-29 01:05:01 +04:00
if ( udev_device = = NULL )
return NULL ;
2008-08-28 00:02:41 +04:00
udev_device - > refcount + + ;
return udev_device ;
}
/**
* udev_device_unref :
* @ udev_device : udev device
*
* Drop a reference of a udev device . If the refcount reaches zero ,
* the ressources of the device will be released .
*
* */
void udev_device_unref ( struct udev_device * udev_device )
{
2008-08-29 01:05:01 +04:00
if ( udev_device = = NULL )
return ;
2008-08-28 00:02:41 +04:00
udev_device - > refcount - - ;
if ( udev_device - > refcount > 0 )
return ;
2008-09-12 02:58:40 +04:00
if ( udev_device - > parent_device ! = NULL )
udev_device_unref ( udev_device - > parent_device ) ;
2008-09-01 20:52:22 +04:00
free ( udev_device - > syspath ) ;
2008-09-26 21:43:32 +04:00
free ( udev_device - > devnode ) ;
2008-08-29 01:05:01 +04:00
free ( udev_device - > subsystem ) ;
2008-09-26 21:43:32 +04:00
list_cleanup ( udev_device - > udev , & udev_device - > devlink_list ) ;
2008-09-25 15:20:27 +04:00
list_cleanup ( udev_device - > udev , & udev_device - > properties_list ) ;
2008-09-09 19:38:10 +04:00
free ( udev_device - > action ) ;
free ( udev_device - > driver ) ;
free ( udev_device - > devpath_old ) ;
free ( udev_device - > physdevpath ) ;
2008-09-25 15:20:27 +04:00
list_cleanup ( udev_device - > udev , & udev_device - > attr_list ) ;
2008-09-06 17:45:31 +04:00
info ( udev_device - > udev , " udev_device: %p released \n " , udev_device ) ;
2008-08-28 00:02:41 +04:00
free ( udev_device ) ;
}
/**
* udev_device_get_devpath :
* @ udev_device : udev device
*
2008-09-01 20:52:22 +04:00
* Retrieve the kernel devpath value of the udev device . The path
* does not contain the sys mount point , and starts with a ' / ' .
2008-08-28 00:02:41 +04:00
*
2008-09-01 20:52:22 +04:00
* Returns : the devpath of the udev device
2008-08-28 00:02:41 +04:00
* */
const char * udev_device_get_devpath ( struct udev_device * udev_device )
{
2008-08-29 01:05:01 +04:00
if ( udev_device = = NULL )
return NULL ;
return udev_device - > devpath ;
2008-08-28 00:02:41 +04:00
}
2008-09-01 20:52:22 +04:00
/**
* udev_device_get_syspath :
* @ udev_device : udev device
*
* Retrieve the sys path of the udev device . The path is an
* absolute path and starts with the sys mount point .
*
* Returns : the sys path of the udev device
* */
const char * udev_device_get_syspath ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return NULL ;
return udev_device - > syspath ;
}
2008-09-11 19:08:12 +04:00
const char * udev_device_get_sysname ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return NULL ;
return udev_device - > sysname ;
}
2008-08-28 00:02:41 +04:00
/**
2008-09-20 11:01:20 +04:00
* udev_device_get_devnode :
2008-08-28 00:02:41 +04:00
* @ udev_device : udev device
*
* Retrieve the device node file name belonging to the udev device .
2008-08-29 01:05:01 +04:00
* The path is an absolute path , and starts with the device directory .
2008-08-28 00:02:41 +04:00
*
* Returns : the device node file name of the udev device , or # NULL if no device node exists
* */
2008-09-20 11:01:20 +04:00
const char * udev_device_get_devnode ( struct udev_device * udev_device )
2008-08-28 00:02:41 +04:00
{
2008-08-29 01:05:01 +04:00
if ( udev_device = = NULL )
2008-08-28 00:02:41 +04:00
return NULL ;
2008-09-26 21:43:32 +04:00
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
return udev_device - > devnode ;
2008-08-28 00:02:41 +04:00
}
/**
* udev_device_get_subsystem :
* @ udev_device : udev device
*
* Retrieve the subsystem string of the udev device . The string does not
* contain any " / " .
*
* Returns : the subsystem name of the udev device , or # NULL if it can not be determined
* */
const char * udev_device_get_subsystem ( struct udev_device * udev_device )
{
2008-09-10 23:50:21 +04:00
char subsystem [ UTIL_NAME_SIZE ] ;
2008-08-29 01:05:01 +04:00
if ( udev_device = = NULL )
return NULL ;
if ( udev_device - > subsystem ! = NULL )
return udev_device - > subsystem ;
2008-09-15 22:19:56 +04:00
/* read "subsytem" link */
2008-09-18 10:58:38 +04:00
if ( util_get_sys_subsystem ( udev_device - > udev , udev_device - > syspath , subsystem , sizeof ( subsystem ) ) > 0 ) {
2008-09-15 22:19:56 +04:00
udev_device - > subsystem = strdup ( subsystem ) ;
return udev_device - > subsystem ;
}
/* implicit names */
if ( strncmp ( udev_device - > devpath , " /module/ " , 8 ) = = 0 ) {
udev_device - > subsystem = strdup ( " module " ) ;
return udev_device - > subsystem ;
}
if ( strstr ( udev_device - > devpath , " /drivers/ " ) ! = NULL ) {
udev_device - > subsystem = strdup ( " drivers " ) ;
return udev_device - > subsystem ;
}
if ( strncmp ( udev_device - > devpath , " /subsystem/ " , 11 ) = = 0 | |
strncmp ( udev_device - > devpath , " /class/ " , 7 ) = = 0 | |
strncmp ( udev_device - > devpath , " /bus/ " , 5 ) = = 0 ) {
udev_device - > subsystem = strdup ( " subsystem " ) ;
return udev_device - > subsystem ;
}
return NULL ;
2008-08-28 00:02:41 +04:00
}
/**
2008-09-28 03:34:55 +04:00
* udev_device_get_devlinks_list_entry :
2008-08-28 00:02:41 +04:00
* @ udev_device : udev device
*
2008-09-25 15:20:27 +04:00
* Retrieve the list of device links pointing to the device file of
* the udev device . The next list entry can be retrieved with
2008-09-26 21:44:53 +04:00
* udev_list_entry_next ( ) , which returns # NULL if no more entries exist .
2008-09-25 15:20:27 +04:00
* The devlink path can be retrieved from the list entry by
2008-09-26 21:44:53 +04:00
* udev_list_entry_get_name ( ) . The path is an absolute path , and starts with
2008-09-25 15:20:27 +04:00
* the device directory .
2008-08-28 00:02:41 +04:00
*
2008-09-25 15:20:27 +04:00
* Returns : the first entry of the device node link list
2008-08-28 00:02:41 +04:00
* */
2008-09-28 03:34:55 +04:00
struct udev_list_entry * udev_device_get_devlinks_list_entry ( struct udev_device * udev_device )
2008-08-28 00:02:41 +04:00
{
2008-09-26 21:43:32 +04:00
if ( udev_device = = NULL )
return NULL ;
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
return list_get_entry ( & udev_device - > devlink_list ) ;
2008-08-28 00:02:41 +04:00
}
/**
2008-09-28 03:34:55 +04:00
* udev_device_get_properties_list_entry :
2008-08-28 00:02:41 +04:00
* @ udev_device : udev device
*
2008-09-25 15:20:27 +04:00
* Retrieve the list of key / value device properties of the udev
2008-09-26 21:44:53 +04:00
* device . The next list entry can be retrieved with udev_list_entry_next ( ) ,
2008-09-25 15:20:27 +04:00
* which returns # NULL if no more entries exist . The property name
* can be retrieved from the list entry by udev_list_get_name ( ) ,
* the property value by udev_list_get_value ( ) .
2008-08-28 00:02:41 +04:00
*
2008-09-25 15:20:27 +04:00
* Returns : the first entry of the property list
2008-08-28 00:02:41 +04:00
* */
2008-09-28 03:34:55 +04:00
struct udev_list_entry * udev_device_get_properties_list_entry ( struct udev_device * udev_device )
2008-08-28 00:02:41 +04:00
{
2008-09-26 21:43:32 +04:00
if ( udev_device = = NULL )
return NULL ;
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
2008-09-25 15:20:27 +04:00
return list_get_entry ( & udev_device - > properties_list ) ;
2008-08-28 00:02:41 +04:00
}
2008-09-01 20:52:22 +04:00
2008-09-09 16:06:20 +04:00
const char * udev_device_get_driver ( struct udev_device * udev_device )
{
2008-09-10 23:50:21 +04:00
char driver [ UTIL_NAME_SIZE ] ;
2008-09-09 20:14:54 +04:00
2008-09-09 16:06:20 +04:00
if ( udev_device = = NULL )
return NULL ;
2008-09-09 20:14:54 +04:00
if ( udev_device - > driver ! = NULL )
return udev_device - > driver ;
2008-09-16 04:12:47 +04:00
if ( util_get_sys_driver ( udev_device - > udev , udev_device - > syspath , driver , sizeof ( driver ) ) < 2 )
2008-09-09 20:14:54 +04:00
return NULL ;
udev_device - > driver = strdup ( driver ) ;
2008-09-09 16:06:20 +04:00
return udev_device - > driver ;
}
dev_t udev_device_get_devnum ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return makedev ( 0 , 0 ) ;
2008-09-26 21:43:32 +04:00
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
2008-09-09 16:06:20 +04:00
return udev_device - > devnum ;
}
const char * udev_device_get_action ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return NULL ;
return udev_device - > action ;
}
2008-09-09 16:37:36 +04:00
unsigned long long int udev_device_get_seqnum ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return 0 ;
return udev_device - > seqnum ;
}
2008-09-13 23:09:28 +04:00
const char * udev_device_get_attr_value ( struct udev_device * udev_device , const char * attr )
{
2008-09-28 03:34:55 +04:00
struct udev_list_entry * list_entry ;
2008-09-13 23:09:28 +04:00
char path [ UTIL_PATH_SIZE ] ;
char value [ UTIL_NAME_SIZE ] ;
struct stat statbuf ;
int fd ;
ssize_t size ;
const char * val = NULL ;
2008-09-15 22:19:56 +04:00
/* look for possibly already cached result */
2008-09-28 03:34:55 +04:00
udev_list_entry_foreach ( list_entry , list_get_entry ( & udev_device - > attr_list ) ) {
if ( strcmp ( udev_list_entry_get_name ( list_entry ) , attr ) = = 0 ) {
info ( udev_device - > udev , " got '%s' (%s) from cache \n " , attr , udev_list_entry_get_value ( list_entry ) ) ;
return udev_list_entry_get_value ( list_entry ) ;
2008-09-15 22:19:56 +04:00
}
}
2008-09-13 23:09:28 +04:00
util_strlcpy ( path , udev_device_get_syspath ( udev_device ) , sizeof ( path ) ) ;
util_strlcat ( path , " / " , sizeof ( path ) ) ;
util_strlcat ( path , attr , sizeof ( path ) ) ;
if ( lstat ( path , & statbuf ) ! = 0 ) {
info ( udev_device - > udev , " stat '%s' failed: %s \n " , path , strerror ( errno ) ) ;
goto out ;
}
if ( S_ISLNK ( statbuf . st_mode ) ) {
/* links return the last element of the target path */
char target [ UTIL_NAME_SIZE ] ;
int len ;
char * pos ;
len = readlink ( path , target , sizeof ( target ) ) ;
if ( len > 0 ) {
target [ len ] = ' \0 ' ;
pos = strrchr ( target , ' / ' ) ;
if ( pos ! = NULL ) {
pos = & pos [ 1 ] ;
info ( udev_device - > udev , " cache '%s' with link value '%s' \n " , attr , pos ) ;
2008-09-28 03:34:55 +04:00
list_entry = list_entry_add ( udev_device - > udev , & udev_device - > attr_list , attr , pos , 0 , 0 ) ;
val = udev_list_entry_get_value ( list_entry ) ;
2008-09-13 23:09:28 +04:00
}
}
goto out ;
}
/* skip directories */
if ( S_ISDIR ( statbuf . st_mode ) )
goto out ;
/* skip non-readable files */
if ( ( statbuf . st_mode & S_IRUSR ) = = 0 )
goto out ;
/* read attribute value */
fd = open ( path , O_RDONLY ) ;
if ( fd < 0 ) {
info ( udev_device - > udev , " attribute '%s' can not be opened \n " , path ) ;
goto out ;
}
size = read ( fd , value , sizeof ( value ) ) ;
close ( fd ) ;
if ( size < 0 )
goto out ;
if ( size = = sizeof ( value ) )
goto out ;
2008-09-15 22:19:56 +04:00
/* got a valid value, store it in cache and return it */
2008-09-13 23:09:28 +04:00
value [ size ] = ' \0 ' ;
util_remove_trailing_chars ( value , ' \n ' ) ;
info ( udev_device - > udev , " '%s' has attribute value '%s' \n " , path , value ) ;
2008-09-28 03:34:55 +04:00
list_entry = list_entry_add ( udev_device - > udev , & udev_device - > attr_list , attr , value , 0 , 0 ) ;
val = udev_list_entry_get_value ( list_entry ) ;
2008-09-13 23:09:28 +04:00
out :
return val ;
}
2008-09-16 04:12:47 +04:00
int device_set_syspath ( struct udev_device * udev_device , const char * syspath )
2008-09-01 20:52:22 +04:00
{
2008-09-16 04:12:47 +04:00
const char * pos ;
udev_device - > syspath = strdup ( syspath ) ;
if ( udev_device - > syspath = = NULL )
2008-09-01 20:52:22 +04:00
return - ENOMEM ;
udev_device - > devpath = & udev_device - > syspath [ strlen ( udev_get_sys_path ( udev_device - > udev ) ) ] ;
2008-09-16 04:12:47 +04:00
pos = strrchr ( udev_device - > syspath , ' / ' ) ;
if ( pos = = NULL )
return - EINVAL ;
udev_device - > sysname = & pos [ 1 ] ;
2008-09-01 20:52:22 +04:00
return 0 ;
}
int device_set_subsystem ( struct udev_device * udev_device , const char * subsystem )
{
udev_device - > subsystem = strdup ( subsystem ) ;
if ( udev_device - > subsystem = = NULL )
return - 1 ;
return 0 ;
}
2008-09-26 21:43:32 +04:00
int device_set_devnode ( struct udev_device * udev_device , const char * devnode )
2008-09-01 20:52:22 +04:00
{
2008-09-26 21:43:32 +04:00
udev_device - > devnode = strdup ( devnode ) ;
if ( udev_device - > devnode = = NULL )
2008-09-01 20:52:22 +04:00
return - ENOMEM ;
return 0 ;
}
int device_add_devlink ( struct udev_device * udev_device , const char * devlink )
{
2008-09-28 03:34:55 +04:00
if ( list_entry_add ( udev_device - > udev , & udev_device - > devlink_list , devlink , NULL , 1 , 0 ) = = NULL )
2008-09-01 20:52:22 +04:00
return - ENOMEM ;
return 0 ;
}
2008-09-15 22:19:56 +04:00
int device_add_property ( struct udev_device * udev_device , const char * key , const char * value )
2008-09-01 20:52:22 +04:00
{
2008-09-28 03:34:55 +04:00
if ( list_entry_add ( udev_device - > udev , & udev_device - > properties_list , key , value , 1 , 0 ) = = NULL )
2008-09-01 20:52:22 +04:00
return - ENOMEM ;
return 0 ;
}
2008-09-09 16:06:20 +04:00
2008-09-15 22:19:56 +04:00
int device_add_property_from_string ( struct udev_device * udev_device , const char * property )
{
char name [ UTIL_PATH_SIZE ] ;
char * val ;
strncpy ( name , property , sizeof ( name ) ) ;
val = strchr ( name , ' = ' ) ;
if ( val = = NULL )
return - 1 ;
val [ 0 ] = ' \0 ' ;
val = & val [ 1 ] ;
if ( val [ 0 ] = = ' \0 ' )
val = NULL ;
device_add_property ( udev_device , name , val ) ;
return 0 ;
}
2008-09-09 16:06:20 +04:00
int device_set_action ( struct udev_device * udev_device , const char * action )
{
udev_device - > action = strdup ( action ) ;
if ( udev_device - > action = = NULL )
return - ENOMEM ;
return 0 ;
}
int device_set_driver ( struct udev_device * udev_device , const char * driver )
{
udev_device - > driver = strdup ( driver ) ;
if ( udev_device - > driver = = NULL )
return - ENOMEM ;
return 0 ;
}
const char * device_get_devpath_old ( struct udev_device * udev_device )
{
return udev_device - > devpath_old ;
}
int device_set_devpath_old ( struct udev_device * udev_device , const char * devpath_old )
{
udev_device - > devpath_old = strdup ( devpath_old ) ;
if ( udev_device - > devpath_old = = NULL )
return - ENOMEM ;
return 0 ;
}
const char * device_get_physdevpath ( struct udev_device * udev_device )
{
return udev_device - > physdevpath ;
}
int device_set_physdevpath ( struct udev_device * udev_device , const char * physdevpath )
{
udev_device - > physdevpath = strdup ( physdevpath ) ;
if ( udev_device - > physdevpath = = NULL )
return - ENOMEM ;
return 0 ;
}
int device_get_timeout ( struct udev_device * udev_device )
{
return udev_device - > timeout ;
}
int device_set_timeout ( struct udev_device * udev_device , int timeout )
{
udev_device - > timeout = timeout ;
return 0 ;
}
2008-09-26 21:43:32 +04:00
int device_get_event_timeout ( struct udev_device * udev_device )
{
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
return udev_device - > event_timeout ;
}
int device_set_event_timeout ( struct udev_device * udev_device , int event_timeout )
{
udev_device - > event_timeout = event_timeout ;
return 0 ;
}
2008-09-09 16:06:20 +04:00
2008-09-09 16:37:36 +04:00
int device_set_seqnum ( struct udev_device * udev_device , unsigned long long int seqnum )
{
udev_device - > seqnum = seqnum ;
return 0 ;
}
2008-09-09 16:06:20 +04:00
int device_set_devnum ( struct udev_device * udev_device , dev_t devnum )
{
udev_device - > devnum = devnum ;
return 0 ;
}
2008-09-10 12:09:34 +04:00
int device_get_num_fake_partitions ( struct udev_device * udev_device )
{
2008-09-26 21:43:32 +04:00
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
2008-09-10 12:09:34 +04:00
return udev_device - > num_fake_partitions ;
}
int device_set_num_fake_partitions ( struct udev_device * udev_device , int num )
{
udev_device - > num_fake_partitions = num ;
2008-09-10 16:17:36 +04:00
return 0 ;
2008-09-10 12:09:34 +04:00
}
2008-09-10 16:17:36 +04:00
int device_get_devlink_priority ( struct udev_device * udev_device )
2008-09-10 12:09:34 +04:00
{
2008-09-26 21:43:32 +04:00
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
2008-09-10 16:17:36 +04:00
return udev_device - > devlink_priority ;
2008-09-10 12:09:34 +04:00
}
2008-09-10 16:17:36 +04:00
int device_set_devlink_priority ( struct udev_device * udev_device , int prio )
2008-09-10 12:09:34 +04:00
{
2008-09-10 16:17:36 +04:00
udev_device - > devlink_priority = prio ;
return 0 ;
2008-09-10 12:09:34 +04:00
}
int device_get_ignore_remove ( struct udev_device * udev_device )
{
2008-09-26 21:43:32 +04:00
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
2008-09-10 12:09:34 +04:00
return udev_device - > ignore_remove ;
}
int device_set_ignore_remove ( struct udev_device * udev_device , int ignore )
{
2008-09-10 16:17:36 +04:00
udev_device - > ignore_remove = ignore ;
return 0 ;
2008-09-10 12:09:34 +04:00
}
2008-09-10 16:17:36 +04:00