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-13 23:09:28 +04:00
# include <fcntl.h>
2008-10-14 21:53:47 +04:00
# include <ctype.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 {
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 ;
2008-10-14 21:53:47 +04:00
char * sysname ;
const char * sysnum ;
2008-09-26 21:43:32 +04:00
char * devnode ;
2008-09-01 20:52:22 +04:00
char * subsystem ;
2009-01-02 06:14:47 +03:00
char * devtype ;
2008-10-15 16:21:33 +04:00
char * driver ;
2008-09-09 16:06:20 +04:00
char * action ;
char * devpath_old ;
char * physdevpath ;
2008-10-26 05:39:41 +03:00
char * * envp ;
2008-10-24 18:36:27 +04:00
char * monitor_buf ;
size_t monitor_buf_len ;
2008-10-23 04:57:08 +04:00
struct udev_list_node devlinks_list ;
struct udev_list_node properties_list ;
struct udev_list_node sysattr_list ;
2008-09-10 12:09:34 +04:00
unsigned long long int seqnum ;
2008-10-23 04:57:08 +04:00
int event_timeout ;
int timeout ;
2008-09-10 12:09:34 +04:00
int num_fake_partitions ;
2008-09-10 16:17:36 +04:00
int devlink_priority ;
2008-10-23 04:57:08 +04:00
int refcount ;
dev_t devnum ;
2009-02-23 20:31:26 +03:00
int watch_handle ;
2008-10-23 04:57:08 +04:00
unsigned int parent_set : 1 ;
unsigned int subsystem_set : 1 ;
2009-01-02 06:14:47 +03:00
unsigned int devtype_set : 1 ;
2008-10-23 04:57:08 +04:00
unsigned int devlinks_uptodate : 1 ;
unsigned int envp_uptodate : 1 ;
unsigned int driver_set : 1 ;
unsigned int info_loaded : 1 ;
unsigned int ignore_remove : 1 ;
2008-09-01 20:52:22 +04:00
} ;
2008-10-11 20:40:33 +04:00
static size_t devpath_to_db_path ( struct udev * udev , const char * devpath , char * filename , size_t len )
2008-09-10 16:17:36 +04:00
{
size_t start ;
/* translate to location of db file */
2008-10-11 20:40:33 +04:00
util_strlcpy ( filename , udev_get_dev_path ( udev ) , len ) ;
2008-09-10 20:00:31 +04:00
start = util_strlcat ( filename , " /.udev/db/ " , len ) ;
2008-10-11 20:40:33 +04:00
util_strlcat ( filename , 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
}
2008-11-05 14:23:06 +03:00
int udev_device_read_db ( struct udev_device * udev_device )
2008-09-10 16:17:36 +04:00
{
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-10-11 20:40:33 +04:00
devpath_to_db_path ( udev_device - > udev , udev_device - > devpath , filename , sizeof ( filename ) ) ;
2008-09-10 16:17:36 +04:00
if ( lstat ( filename , & stats ) ! = 0 ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " no db file to read %s: %m \n " , filename ) ;
2008-09-10 16:17:36 +04:00
return - 1 ;
}
if ( ( stats . st_mode & S_IFMT ) = = S_IFLNK ) {
2008-09-10 20:00:31 +04:00
char target [ UTIL_PATH_SIZE ] ;
2008-10-14 21:53:47 +04:00
char devnode [ UTIL_PATH_SIZE ] ;
2008-09-10 16:17:36 +04:00
int target_len ;
2008-10-06 15:52:43 +04:00
char * next ;
2008-09-10 16:17:36 +04:00
target_len = readlink ( filename , target , sizeof ( target ) ) ;
if ( target_len > 0 )
target [ target_len ] = ' \0 ' ;
else {
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " error reading db link %s: %m \n " , filename ) ;
2008-09-10 16:17:36 +04:00
return - 1 ;
}
2008-10-06 15:52:43 +04:00
next = strchr ( target , ' ' ) ;
if ( next ! = NULL ) {
next [ 0 ] = ' \0 ' ;
next = & next [ 1 ] ;
}
2008-10-14 21:53:47 +04:00
util_strlcpy ( devnode , udev_get_dev_path ( udev_device - > udev ) , sizeof ( devnode ) ) ;
util_strlcat ( devnode , " / " , sizeof ( devnode ) ) ;
util_strlcat ( devnode , target , sizeof ( devnode ) ) ;
udev_device_set_devnode ( udev_device , devnode ) ;
2008-10-06 15:52:43 +04:00
while ( next ! = NULL ) {
2008-10-14 21:53:47 +04:00
char devlink [ UTIL_PATH_SIZE ] ;
2008-10-06 15:52:43 +04:00
const char * lnk ;
lnk = next ;
next = strchr ( next , ' ' ) ;
if ( next ! = NULL ) {
next [ 0 ] = ' \0 ' ;
next = & next [ 1 ] ;
}
2008-10-14 21:53:47 +04:00
util_strlcpy ( devlink , udev_get_dev_path ( udev_device - > udev ) , sizeof ( devlink ) ) ;
util_strlcat ( devlink , " / " , sizeof ( devlink ) ) ;
util_strlcat ( devlink , lnk , sizeof ( devlink ) ) ;
udev_device_add_devlink ( udev_device , devlink ) ;
2008-10-06 15:52:43 +04:00
}
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 ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " error reading db file %s: %m \n " , filename ) ;
2008-09-10 16:17:36 +04:00
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-10-14 21:53:47 +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 ) ) ;
udev_device_set_devnode ( udev_device , filename ) ;
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-10-10 00:24:43 +04:00
udev_device_add_devlink ( udev_device , filename ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' L ' :
2008-10-10 00:24:43 +04:00
udev_device_set_devlink_priority ( udev_device , atoi ( val ) ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' T ' :
2008-10-10 00:24:43 +04:00
udev_device_set_event_timeout ( udev_device , atoi ( val ) ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' A ' :
2008-10-10 00:24:43 +04:00
udev_device_set_num_fake_partitions ( udev_device , atoi ( val ) ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' R ' :
2008-10-10 00:24:43 +04:00
udev_device_set_ignore_remove ( udev_device , atoi ( val ) ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' E ' :
2008-10-10 00:24:43 +04:00
udev_device_add_property_from_string ( udev_device , val ) ;
2008-09-10 16:17:36 +04:00
break ;
2009-02-23 20:31:26 +03:00
case ' W ' :
udev_device_set_watch_handle ( udev_device , atoi ( val ) ) ;
break ;
2008-09-10 16:17:36 +04:00
}
}
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-10-15 18:56:06 +04:00
int udev_device_read_uevent_file ( struct udev_device * udev_device )
2008-09-26 21:43:32 +04:00
{
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 ' ;
2009-01-02 06:14:47 +03:00
if ( strncmp ( line , " DEVTYPE= " , 8 ) = = 0 )
udev_device_set_devtype ( udev_device , & line [ 8 ] ) ;
else if ( strncmp ( line , " MAJOR= " , 6 ) = = 0 )
2008-09-26 21:43:32 +04:00
maj = strtoull ( & line [ 6 ] , NULL , 10 ) ;
else if ( strncmp ( line , " MINOR= " , 6 ) = = 0 )
min = strtoull ( & line [ 6 ] , NULL , 10 ) ;
2008-10-10 00:24:43 +04:00
udev_device_add_property_from_string ( udev_device , line ) ;
2008-09-26 21:43:32 +04:00
}
udev_device - > devnum = makedev ( maj , min ) ;
fclose ( f ) ;
return 0 ;
}
2008-11-05 14:23:06 +03:00
static void device_load_info ( struct udev_device * device )
2008-09-26 21:43:32 +04:00
{
2008-10-14 21:53:47 +04:00
device - > info_loaded = 1 ;
2008-10-15 18:56:06 +04:00
udev_device_read_uevent_file ( device ) ;
2008-11-05 14:23:06 +03:00
udev_device_read_db ( device ) ;
2008-09-26 21:43:32 +04:00
}
2008-10-10 00:24:43 +04:00
void udev_device_set_info_loaded ( struct udev_device * device )
2008-09-26 21:43:32 +04:00
{
device - > info_loaded = 1 ;
}
2008-09-30 18:16:29 +04:00
struct udev_device * device_new ( struct udev * udev )
2008-08-28 00:02:41 +04:00
{
struct udev_device * udev_device ;
2008-10-16 15:53:16 +04:00
struct udev_list_entry * list_entry ;
2008-08-28 00:02:41 +04:00
2008-08-29 01:05:01 +04:00
if ( udev = = NULL )
return NULL ;
2008-10-21 14:10:32 +04:00
udev_device = calloc ( 1 , sizeof ( struct udev_device ) ) ;
2008-08-28 00:02:41 +04:00
if ( udev_device = = NULL )
return NULL ;
udev_device - > refcount = 1 ;
udev_device - > udev = udev ;
2008-10-14 21:53:47 +04:00
udev_list_init ( & udev_device - > devlinks_list ) ;
2008-10-10 00:24:43 +04:00
udev_list_init ( & udev_device - > properties_list ) ;
2008-10-20 20:12:36 +04:00
udev_list_init ( & udev_device - > sysattr_list ) ;
2008-10-15 16:21:33 +04:00
udev_device - > event_timeout = - 1 ;
2009-02-23 20:31:26 +03:00
udev_device - > watch_handle = - 1 ;
2008-10-16 15:53:16 +04:00
/* copy global properties */
udev_list_entry_foreach ( list_entry , udev_get_properties_list_entry ( udev ) )
udev_device_add_property ( udev_device ,
udev_list_entry_get_name ( list_entry ) ,
udev_list_entry_get_value ( list_entry ) ) ;
2008-11-01 22:16:24 +03:00
dbg ( 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
2008-10-26 17:48:48 +03:00
* release the resources of the udev device .
2008-08-28 00:02:41 +04:00
*
* 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 ;
2008-09-10 20:00:31 +04:00
char path [ UTIL_PATH_SIZE ] ;
2008-10-01 12:22:47 +04:00
char * pos ;
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 , ' / ' ) ;
2009-03-18 20:42:16 +03:00
if ( pos = = NULL | | pos [ 1 ] = = ' \0 ' | | pos < & subdir [ 2 ] ) {
2008-11-01 22:16:24 +03:00
dbg ( 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
2008-10-01 12:22:47 +04:00
/* try to resolve the silly block layout if needed */
if ( strncmp ( & path [ len ] , " /block/ " , 7 ) = = 0 ) {
char block [ UTIL_PATH_SIZE ] ;
char part [ UTIL_PATH_SIZE ] ;
util_strlcpy ( block , path , sizeof ( block ) ) ;
pos = strrchr ( block , ' / ' ) ;
if ( pos = = NULL )
return NULL ;
util_strlcpy ( part , pos , sizeof ( part ) ) ;
pos [ 0 ] = ' \0 ' ;
if ( util_resolve_sys_link ( udev , block , sizeof ( block ) ) = = 0 ) {
util_strlcpy ( path , block , sizeof ( path ) ) ;
util_strlcat ( path , part , 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 ) {
2008-11-01 22:16:24 +03:00
dbg ( udev , " not a device: %s \n " , syspath ) ;
2008-09-28 05:34:57 +04:00
return NULL ;
}
} else {
/* everything else just needs to be a directory */
if ( stat ( path , & statbuf ) ! = 0 | | ! S_ISDIR ( statbuf . st_mode ) ) {
2008-11-01 22:16:24 +03:00
dbg ( udev , " directory not found: %s \n " , syspath ) ;
2008-09-28 05:34:57 +04:00
return NULL ;
}
}
2008-09-30 18:16:29 +04:00
udev_device = device_new ( udev ) ;
2008-09-28 05:34:57 +04:00
if ( udev_device = = NULL )
return NULL ;
2008-10-10 00:24:43 +04:00
udev_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-30 15:42:26 +04:00
udev_enumerate_add_match_subsystem ( udev_enumerate , " block " ) ;
2008-09-28 19:39:31 +04:00
else if ( type = = ' c ' )
2008-09-30 15:42:26 +04:00
udev_enumerate_add_nomatch_subsystem ( udev_enumerate , " block " ) ;
udev_enumerate_scan_devices ( udev_enumerate ) ;
2008-09-29 04:00:17 +04:00
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-30 15:42:26 +04:00
if ( type = = ' b ' & & strcmp ( udev_device_get_subsystem ( device_loop ) , " block " ) ! = 0 )
2008-09-28 19:39:31 +04:00
continue ;
2008-09-30 15:42:26 +04:00
if ( type = = ' c ' & & strcmp ( udev_device_get_subsystem ( device_loop ) , " block " ) = = 0 )
2008-09-28 19:39:31 +04:00
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-10-07 22:20:34 +04:00
struct udev_device * udev_device_new_from_subsystem_sysname ( struct udev * udev , const char * subsystem , const char * sysname )
{
size_t sys_path_len ;
char path_full [ UTIL_PATH_SIZE ] ;
char * path ;
struct stat statbuf ;
sys_path_len = util_strlcpy ( path_full , udev_get_sys_path ( udev ) , sizeof ( path_full ) ) ;
path = & path_full [ sys_path_len ] ;
if ( strcmp ( subsystem , " subsystem " ) = = 0 ) {
util_strlcpy ( path , " /subsystem/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , sysname , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
util_strlcpy ( path , " /bus/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , sysname , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
util_strlcpy ( path , " /class/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , sysname , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
goto out ;
}
if ( strcmp ( subsystem , " module " ) = = 0 ) {
util_strlcpy ( path , " /module/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , sysname , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
goto out ;
}
if ( strcmp ( subsystem , " drivers " ) = = 0 ) {
char subsys [ UTIL_NAME_SIZE ] ;
char * driver ;
util_strlcpy ( subsys , sysname , sizeof ( subsys ) ) ;
driver = strchr ( subsys , ' : ' ) ;
if ( driver ! = NULL ) {
driver [ 0 ] = ' \0 ' ;
driver = & driver [ 1 ] ;
util_strlcpy ( path , " /subsystem/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , subsys , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , " /drivers/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , driver , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
util_strlcpy ( path , " /bus/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , subsys , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , " /drivers/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , driver , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
}
goto out ;
}
util_strlcpy ( path , " /subsystem/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , subsystem , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , " /devices/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , sysname , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
util_strlcpy ( path , " /bus/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , subsystem , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , " /devices/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , sysname , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
util_strlcpy ( path , " /class/ " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , subsystem , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , " / " , sizeof ( path_full ) - sys_path_len ) ;
util_strlcat ( path , sysname , sizeof ( path_full ) - sys_path_len ) ;
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
out :
return NULL ;
found :
return udev_device_new_from_syspath ( udev , path_full ) ;
}
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 ) ) ;
2008-11-14 20:26:49 +03:00
if ( util_resolve_sys_link ( udev_device - > udev , path , sizeof ( path ) ) = = 0 ) {
2008-09-28 05:34:57 +04:00
udev_device_parent = udev_device_new_from_syspath ( udev_device - > udev , path ) ;
2008-11-14 20:26:49 +03:00
if ( udev_device_parent ! = NULL )
return udev_device_parent ;
}
2008-09-28 05:34:57 +04:00
}
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-10-16 13:37:22 +04:00
if ( ! udev_device - > parent_set ) {
udev_device - > parent_set = 1 ;
udev_device - > parent_device = device_new_from_parent ( udev_device ) ;
2008-09-15 22:19:56 +04:00
}
2008-10-16 13:37:22 +04:00
if ( udev_device - > parent_device ! = NULL )
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " returning existing parent %p \n " , udev_device - > parent_device ) ;
2008-09-12 02:58:40 +04:00
return udev_device - > parent_device ;
}
2009-01-03 13:10:10 +03:00
struct udev_device * udev_device_get_parent_with_subsystem_devtype ( struct udev_device * udev_device , const char * subsystem , const char * devtype )
2009-01-02 06:14:47 +03:00
{
struct udev_device * parent ;
2009-01-03 13:10:10 +03:00
if ( subsystem = = NULL )
return NULL ;
2009-01-02 06:14:47 +03:00
parent = udev_device_get_parent ( udev_device ) ;
while ( parent ! = NULL ) {
2009-01-03 13:10:10 +03:00
const char * parent_subsystem ;
2009-01-02 06:14:47 +03:00
const char * parent_devtype ;
2009-01-03 13:10:10 +03:00
parent_subsystem = udev_device_get_subsystem ( parent ) ;
if ( parent_subsystem ! = NULL & & strcmp ( parent_subsystem , subsystem ) = = 0 ) {
if ( devtype = = NULL )
break ;
parent_devtype = udev_device_get_devtype ( parent ) ;
if ( parent_devtype ! = NULL & & strcmp ( parent_devtype , devtype ) = = 0 )
break ;
}
2009-01-02 06:14:47 +03:00
parent = udev_device_get_parent ( parent ) ;
}
return parent ;
}
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 ,
2008-10-26 17:48:48 +03:00
* the resources of the device will be released .
2008-08-28 00:02:41 +04:00
*
* */
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-10-14 21:53:47 +04:00
free ( udev_device - > sysname ) ;
2008-09-26 21:43:32 +04:00
free ( udev_device - > devnode ) ;
2008-08-29 01:05:01 +04:00
free ( udev_device - > subsystem ) ;
2009-01-02 06:14:47 +03:00
free ( udev_device - > devtype ) ;
2008-10-18 21:27:38 +04:00
udev_list_cleanup_entries ( udev_device - > udev , & udev_device - > devlinks_list ) ;
udev_list_cleanup_entries ( 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-10-20 20:12:36 +04:00
udev_list_cleanup_entries ( udev_device - > udev , & udev_device - > sysattr_list ) ;
2008-10-26 05:39:41 +03:00
free ( udev_device - > envp ) ;
2008-10-24 18:36:27 +04:00
free ( udev_device - > monitor_buf ) ;
2008-11-01 22:16:24 +03:00
dbg ( 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-10-14 21:53:47 +04:00
const char * udev_device_get_sysnum ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return NULL ;
return udev_device - > sysnum ;
}
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 )
2008-11-05 14:23:06 +03:00
device_load_info ( udev_device ) ;
2008-09-26 21:43:32 +04:00
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 ;
2008-10-15 20:34:14 +04:00
if ( ! udev_device - > subsystem_set ) {
udev_device - > subsystem_set = 1 ;
/* read "subsytem" link */
if ( util_get_sys_subsystem ( udev_device - > udev , udev_device - > syspath , subsystem , sizeof ( subsystem ) ) > 0 ) {
udev_device_set_subsystem ( udev_device , subsystem ) ;
return udev_device - > subsystem ;
}
/* implicit names */
if ( strncmp ( udev_device - > devpath , " /module/ " , 8 ) = = 0 ) {
udev_device_set_subsystem ( udev_device , " module " ) ;
return udev_device - > subsystem ;
}
if ( strstr ( udev_device - > devpath , " /drivers/ " ) ! = NULL ) {
udev_device_set_subsystem ( udev_device , " 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_set_subsystem ( udev_device , " subsystem " ) ;
return udev_device - > subsystem ;
}
2008-09-15 22:19:56 +04:00
}
2008-10-15 20:34:14 +04:00
return udev_device - > subsystem ;
2008-08-28 00:02:41 +04:00
}
2009-01-02 06:14:47 +03:00
/**
* udev_device_get_devtype :
* @ udev_device : udev device
*
* Retrieve the devtype string of the udev device .
*
* Returns : the devtype name of the udev device , or # NULL if it can not be determined
* */
const char * udev_device_get_devtype ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return NULL ;
if ( ! udev_device - > devtype_set ) {
udev_device - > devtype_set = 1 ;
2009-01-03 06:55:15 +03:00
if ( ! udev_device - > info_loaded )
udev_device_read_uevent_file ( udev_device ) ;
2009-01-02 06:14:47 +03:00
}
return udev_device - > devtype ;
}
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 )
2008-11-05 14:23:06 +03:00
device_load_info ( udev_device ) ;
2008-10-14 21:53:47 +04:00
return udev_list_get_entry ( & udev_device - > devlinks_list ) ;
2008-08-28 00:02:41 +04:00
}
2008-10-15 16:21:33 +04:00
void udev_device_cleanup_devlinks_list ( struct udev_device * udev_device )
{
2008-10-15 18:56:06 +04:00
udev_device - > devlinks_uptodate = 0 ;
2008-10-18 21:27:38 +04:00
udev_list_cleanup_entries ( udev_device - > udev , & udev_device - > devlinks_list ) ;
2008-10-15 16:21:33 +04:00
}
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 )
2008-11-05 14:23:06 +03:00
device_load_info ( udev_device ) ;
2008-10-15 18:56:06 +04:00
if ( ! udev_device - > devlinks_uptodate ) {
char symlinks [ UTIL_PATH_SIZE ] ;
struct udev_list_entry * list_entry ;
udev_device - > devlinks_uptodate = 1 ;
list_entry = udev_device_get_devlinks_list_entry ( udev_device ) ;
if ( list_entry ! = NULL ) {
util_strlcpy ( symlinks , udev_list_entry_get_name ( list_entry ) , sizeof ( symlinks ) ) ;
udev_list_entry_foreach ( list_entry , udev_list_entry_get_next ( list_entry ) ) {
util_strlcat ( symlinks , " " , sizeof ( symlinks ) ) ;
util_strlcat ( symlinks , udev_list_entry_get_name ( list_entry ) , sizeof ( symlinks ) ) ;
}
udev_device_add_property ( udev_device , " DEVLINKS " , symlinks ) ;
}
}
2008-10-10 00:24:43 +04:00
return udev_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-10-15 20:34:14 +04:00
if ( ! udev_device - > driver_set ) {
udev_device - > driver_set = 1 ;
if ( util_get_sys_driver ( udev_device - > udev , udev_device - > syspath , driver , sizeof ( driver ) ) > 0 )
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 )
2008-11-05 14:23:06 +03:00
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-10-20 20:12:36 +04:00
const char * udev_device_get_sysattr_value ( struct udev_device * udev_device , const char * sysattr )
2008-09-13 23:09:28 +04:00
{
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 ] ;
2009-01-14 23:54:31 +03:00
char value [ 4096 ] ;
2008-09-13 23:09:28 +04:00
struct stat statbuf ;
int fd ;
ssize_t size ;
const char * val = NULL ;
2008-10-14 21:53:47 +04:00
if ( udev_device = = NULL )
return NULL ;
2008-10-20 20:12:36 +04:00
if ( sysattr = = NULL )
2008-10-14 21:53:47 +04:00
return NULL ;
2008-09-15 22:19:56 +04:00
/* look for possibly already cached result */
2008-10-20 20:12:36 +04:00
udev_list_entry_foreach ( list_entry , udev_list_get_entry ( & udev_device - > sysattr_list ) ) {
if ( strcmp ( udev_list_entry_get_name ( list_entry ) , sysattr ) = = 0 ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " got '%s' (%s) from cache \n " ,
sysattr , udev_list_entry_get_value ( list_entry ) ) ;
2008-09-28 03:34:55 +04:00
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 ) ) ;
2008-10-20 20:12:36 +04:00
util_strlcat ( path , sysattr , sizeof ( path ) ) ;
2008-09-13 23:09:28 +04:00
if ( lstat ( path , & statbuf ) ! = 0 ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " no attribute '%s', keep negative entry \n " , path ) ;
2008-10-20 20:12:36 +04:00
udev_list_entry_add ( udev_device - > udev , & udev_device - > sysattr_list , sysattr , NULL , 0 , 0 ) ;
2008-09-13 23:09:28 +04:00
goto out ;
}
if ( S_ISLNK ( statbuf . st_mode ) ) {
char target [ UTIL_NAME_SIZE ] ;
int len ;
char * pos ;
2008-11-17 04:01:37 +03:00
/* some core links return the last element of the target path */
if ( strcmp ( sysattr , " driver " ) ! = 0 & &
strcmp ( sysattr , " subsystem " ) ! = 0 & &
strcmp ( sysattr , " module " ) ! = 0 )
goto out ;
2008-09-13 23:09:28 +04:00
len = readlink ( path , target , sizeof ( target ) ) ;
if ( len > 0 ) {
target [ len ] = ' \0 ' ;
pos = strrchr ( target , ' / ' ) ;
if ( pos ! = NULL ) {
pos = & pos [ 1 ] ;
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " cache '%s' with link value '%s' \n " , sysattr , pos ) ;
2008-10-20 20:12:36 +04:00
list_entry = udev_list_entry_add ( udev_device - > udev , & udev_device - > sysattr_list , sysattr , pos , 0 , 0 ) ;
2008-09-28 03:34:55 +04:00
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 ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " attribute '%s' can not be opened \n " , path ) ;
2008-09-13 23:09:28 +04:00
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 ' ) ;
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " '%s' has attribute value '%s' \n " , path , value ) ;
2008-10-20 20:12:36 +04:00
list_entry = udev_list_entry_add ( udev_device - > udev , & udev_device - > sysattr_list , sysattr , value , 0 , 0 ) ;
2008-09-28 03:34:55 +04:00
val = udev_list_entry_get_value ( list_entry ) ;
2008-09-13 23:09:28 +04:00
out :
return val ;
}
2008-10-14 21:53:47 +04:00
2008-10-10 00:24:43 +04:00
int udev_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 ;
2008-10-14 21:53:47 +04:00
size_t len ;
2008-09-16 04:12:47 +04:00
2008-10-10 00:24:43 +04:00
free ( udev_device - > syspath ) ;
2008-09-16 04:12:47 +04:00
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-10-11 20:40:33 +04:00
udev_device_add_property ( udev_device , " DEVPATH " , udev_device - > devpath ) ;
2008-10-14 21:53:47 +04:00
2008-09-16 04:12:47 +04:00
pos = strrchr ( udev_device - > syspath , ' / ' ) ;
if ( pos = = NULL )
return - EINVAL ;
2008-10-14 21:53:47 +04:00
udev_device - > sysname = strdup ( & pos [ 1 ] ) ;
if ( udev_device - > sysname = = NULL )
return - ENOMEM ;
/* some devices have '!' in their name, change that to '/' */
len = 0 ;
while ( udev_device - > sysname [ len ] ! = ' \0 ' ) {
if ( udev_device - > sysname [ len ] = = ' ! ' )
udev_device - > sysname [ len ] = ' / ' ;
len + + ;
}
/* trailing number */
2008-10-17 15:19:54 +04:00
while ( len > 0 & & isdigit ( udev_device - > sysname [ - - len ] ) )
2008-10-14 21:53:47 +04:00
udev_device - > sysnum = & udev_device - > sysname [ len ] ;
2008-10-17 15:19:54 +04:00
/* sysname is completely numeric */
if ( len = = 0 )
udev_device - > sysnum = NULL ;
2008-09-01 20:52:22 +04:00
return 0 ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_subsystem ( struct udev_device * udev_device , const char * subsystem )
2008-09-01 20:52:22 +04:00
{
2008-10-15 16:21:33 +04:00
free ( udev_device - > subsystem ) ;
2008-09-01 20:52:22 +04:00
udev_device - > subsystem = strdup ( subsystem ) ;
if ( udev_device - > subsystem = = NULL )
2008-10-11 20:40:33 +04:00
return - ENOMEM ;
2008-10-15 20:34:14 +04:00
udev_device - > subsystem_set = 1 ;
2008-10-11 20:40:33 +04:00
udev_device_add_property ( udev_device , " SUBSYSTEM " , udev_device - > subsystem ) ;
2008-09-01 20:52:22 +04:00
return 0 ;
}
2009-01-02 06:14:47 +03:00
int udev_device_set_devtype ( struct udev_device * udev_device , const char * devtype )
{
free ( udev_device - > devtype ) ;
udev_device - > devtype = strdup ( devtype ) ;
if ( udev_device - > devtype = = NULL )
return - ENOMEM ;
udev_device - > devtype_set = 1 ;
udev_device_add_property ( udev_device , " DEVTYPE " , udev_device - > devtype ) ;
return 0 ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_devnode ( struct udev_device * udev_device , const char * devnode )
2008-09-01 20:52:22 +04:00
{
2008-10-14 21:53:47 +04:00
free ( udev_device - > devnode ) ;
2008-09-26 21:43:32 +04:00
udev_device - > devnode = strdup ( devnode ) ;
2008-10-15 18:56:06 +04:00
if ( devnode = = NULL )
return 0 ;
2008-09-26 21:43:32 +04:00
if ( udev_device - > devnode = = NULL )
2008-09-01 20:52:22 +04:00
return - ENOMEM ;
2008-10-15 16:21:33 +04:00
udev_device_add_property ( udev_device , " DEVNAME " , udev_device - > devnode ) ;
2008-09-01 20:52:22 +04:00
return 0 ;
}
2008-10-10 00:24:43 +04:00
int udev_device_add_devlink ( struct udev_device * udev_device , const char * devlink )
2008-09-01 20:52:22 +04:00
{
2008-10-15 18:56:06 +04:00
udev_device - > devlinks_uptodate = 0 ;
2008-10-14 21:53:47 +04:00
if ( udev_list_entry_add ( udev_device - > udev , & udev_device - > devlinks_list , devlink , NULL , 1 , 0 ) = = NULL )
2008-09-01 20:52:22 +04:00
return - ENOMEM ;
return 0 ;
}
2008-10-14 21:53:47 +04:00
struct udev_list_entry * udev_device_add_property ( struct udev_device * udev_device , const char * key , const char * value )
2008-09-01 20:52:22 +04:00
{
2008-10-15 16:21:33 +04:00
udev_device - > envp_uptodate = 0 ;
2008-10-16 15:53:16 +04:00
if ( value = = NULL ) {
struct udev_list_entry * list_entry ;
list_entry = udev_device_get_properties_list_entry ( udev_device ) ;
list_entry = udev_list_entry_get_by_name ( list_entry , key ) ;
if ( list_entry ! = NULL )
2008-11-04 22:19:01 +03:00
udev_list_entry_delete ( list_entry ) ;
2008-10-16 15:53:16 +04:00
return NULL ;
}
2008-10-14 21:53:47 +04:00
return udev_list_entry_add ( udev_device - > udev , & udev_device - > properties_list , key , value , 1 , 0 ) ;
2008-09-01 20:52:22 +04:00
}
2008-09-09 16:06:20 +04:00
2008-10-14 21:53:47 +04:00
struct udev_list_entry * udev_device_add_property_from_string ( struct udev_device * udev_device , const char * property )
2008-09-15 22:19:56 +04:00
{
char name [ UTIL_PATH_SIZE ] ;
char * val ;
2008-10-22 01:42:15 +04:00
util_strlcpy ( name , property , sizeof ( name ) ) ;
2008-09-15 22:19:56 +04:00
val = strchr ( name , ' = ' ) ;
if ( val = = NULL )
2008-10-14 21:53:47 +04:00
return NULL ;
2008-09-15 22:19:56 +04:00
val [ 0 ] = ' \0 ' ;
val = & val [ 1 ] ;
if ( val [ 0 ] = = ' \0 ' )
val = NULL ;
2008-10-14 21:53:47 +04:00
return udev_device_add_property ( udev_device , name , val ) ;
2008-09-15 22:19:56 +04:00
}
2009-01-06 02:26:28 +03:00
const char * udev_device_get_property_value ( struct udev_device * udev_device , const char * key )
{
struct udev_list_entry * list_entry ;
if ( udev_device = = NULL )
return NULL ;
if ( key = = NULL )
return NULL ;
list_entry = udev_device_get_properties_list_entry ( udev_device ) ;
list_entry = udev_list_entry_get_by_name ( list_entry , key ) ;
return udev_list_entry_get_value ( list_entry ) ;
}
2008-10-26 05:39:41 +03:00
# define ENVP_SIZE 128
# define MONITOR_BUF_SIZE 4096
static int update_envp_monitor_buf ( struct udev_device * udev_device )
2008-10-15 16:21:33 +04:00
{
2008-10-26 05:39:41 +03:00
const char * action ;
struct udev_list_entry * list_entry ;
size_t bufpos ;
size_t len ;
unsigned int i ;
2008-10-15 16:21:33 +04:00
2008-10-26 05:39:41 +03:00
/* monitor buffer of property strings */
free ( udev_device - > monitor_buf ) ;
udev_device - > monitor_buf_len = 0 ;
udev_device - > monitor_buf = malloc ( MONITOR_BUF_SIZE ) ;
if ( udev_device - > monitor_buf = = NULL )
return - ENOMEM ;
2008-10-21 14:11:41 +04:00
2008-10-26 05:39:41 +03:00
/* envp array, strings will point into monitor buffer */
2008-10-26 16:31:46 +03:00
if ( udev_device - > envp = = NULL )
udev_device - > envp = malloc ( sizeof ( char * ) * ENVP_SIZE ) ;
2008-10-26 05:39:41 +03:00
if ( udev_device - > envp = = NULL )
return - ENOMEM ;
2008-10-15 16:21:33 +04:00
2008-10-26 05:39:41 +03:00
/* header <action>@<devpath> */
action = udev_device_get_action ( udev_device ) ;
if ( action = = NULL )
return - EINVAL ;
bufpos = util_strlcpy ( udev_device - > monitor_buf , action , MONITOR_BUF_SIZE ) ;
len = util_strlcpy ( & udev_device - > monitor_buf [ bufpos ] , " @ " , MONITOR_BUF_SIZE - bufpos ) ;
if ( len > = MONITOR_BUF_SIZE - bufpos )
return - EINVAL ;
bufpos + = len ;
len = util_strlcpy ( & udev_device - > monitor_buf [ bufpos ] ,
udev_device_get_devpath ( udev_device ) ,
MONITOR_BUF_SIZE - bufpos ) ;
if ( len + 1 > = MONITOR_BUF_SIZE - bufpos )
return - EINVAL ;
bufpos + = len + 1 ;
2008-10-24 18:36:27 +04:00
2008-10-26 05:39:41 +03:00
i = 0 ;
udev_list_entry_foreach ( list_entry , udev_device_get_properties_list_entry ( udev_device ) ) {
/* add string to envp array */
udev_device - > envp [ i + + ] = & udev_device - > monitor_buf [ bufpos ] ;
if ( i + 1 > = ENVP_SIZE )
return - EINVAL ;
2008-10-24 18:36:27 +04:00
2008-10-26 05:39:41 +03:00
/* add property string to monitor buffer */
len = util_strlcpy ( & udev_device - > monitor_buf [ bufpos ] ,
udev_list_entry_get_name ( list_entry ) , MONITOR_BUF_SIZE - bufpos ) ;
if ( len > = MONITOR_BUF_SIZE - bufpos )
2008-10-24 18:36:27 +04:00
return - EINVAL ;
2008-10-26 05:39:41 +03:00
bufpos + = len ;
len = util_strlcpy ( & udev_device - > monitor_buf [ bufpos ] , " = " , MONITOR_BUF_SIZE - bufpos ) ;
2008-10-24 18:36:27 +04:00
if ( len > = MONITOR_BUF_SIZE - bufpos )
return - EINVAL ;
bufpos + = len ;
2008-10-26 05:39:41 +03:00
len = util_strlcpy ( & udev_device - > monitor_buf [ bufpos ] , udev_list_entry_get_value ( list_entry ) ,
2008-10-24 18:36:27 +04:00
MONITOR_BUF_SIZE - bufpos ) ;
if ( len + 1 > = MONITOR_BUF_SIZE - bufpos )
return - EINVAL ;
bufpos + = len + 1 ;
}
2008-10-26 05:39:41 +03:00
udev_device - > envp [ i ] = NULL ;
udev_device - > monitor_buf_len = bufpos ;
udev_device - > envp_uptodate = 1 ;
2008-11-01 22:16:24 +03:00
dbg ( udev_device - > udev , " filled envp/monitor buffer, %u properties, %zu bytes \n " , i , bufpos ) ;
2008-10-26 05:39:41 +03:00
return 0 ;
}
char * * udev_device_get_properties_envp ( struct udev_device * udev_device )
{
if ( ! udev_device - > envp_uptodate )
2008-10-26 06:35:32 +03:00
if ( update_envp_monitor_buf ( udev_device ) ! = 0 )
2008-10-26 05:39:41 +03:00
return NULL ;
return udev_device - > envp ;
}
ssize_t udev_device_get_properties_monitor_buf ( struct udev_device * udev_device , const char * * buf )
{
if ( ! udev_device - > envp_uptodate )
2008-10-26 06:35:32 +03:00
if ( update_envp_monitor_buf ( udev_device ) ! = 0 )
2008-10-26 05:39:41 +03:00
return - EINVAL ;
2008-10-24 18:36:27 +04:00
* buf = udev_device - > monitor_buf ;
return udev_device - > monitor_buf_len ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_action ( struct udev_device * udev_device , const char * action )
2008-09-09 16:06:20 +04:00
{
2008-10-14 21:53:47 +04:00
free ( udev_device - > action ) ;
2008-09-09 16:06:20 +04:00
udev_device - > action = strdup ( action ) ;
if ( udev_device - > action = = NULL )
return - ENOMEM ;
2008-10-16 13:37:22 +04:00
udev_device_add_property ( udev_device , " ACTION " , udev_device - > action ) ;
2008-09-09 16:06:20 +04:00
return 0 ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_driver ( struct udev_device * udev_device , const char * driver )
2008-09-09 16:06:20 +04:00
{
2008-10-15 16:21:33 +04:00
free ( udev_device - > driver ) ;
2008-09-09 16:06:20 +04:00
udev_device - > driver = strdup ( driver ) ;
if ( udev_device - > driver = = NULL )
return - ENOMEM ;
2008-10-15 20:34:14 +04:00
udev_device - > driver_set = 1 ;
2008-10-16 13:37:22 +04:00
udev_device_add_property ( udev_device , " DRIVER " , udev_device - > driver ) ;
2008-09-09 16:06:20 +04:00
return 0 ;
}
2008-10-10 00:24:43 +04:00
const char * udev_device_get_devpath_old ( struct udev_device * udev_device )
2008-09-09 16:06:20 +04:00
{
return udev_device - > devpath_old ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_devpath_old ( struct udev_device * udev_device , const char * devpath_old )
2008-09-09 16:06:20 +04:00
{
udev_device - > devpath_old = strdup ( devpath_old ) ;
if ( udev_device - > devpath_old = = NULL )
return - ENOMEM ;
2008-10-16 13:37:22 +04:00
udev_device_add_property ( udev_device , " DEVPATH_OLD " , udev_device - > devpath_old ) ;
2008-09-09 16:06:20 +04:00
return 0 ;
}
2008-10-10 00:24:43 +04:00
const char * udev_device_get_physdevpath ( struct udev_device * udev_device )
2008-09-09 16:06:20 +04:00
{
return udev_device - > physdevpath ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_physdevpath ( struct udev_device * udev_device , const char * physdevpath )
2008-09-09 16:06:20 +04:00
{
udev_device - > physdevpath = strdup ( physdevpath ) ;
if ( udev_device - > physdevpath = = NULL )
return - ENOMEM ;
return 0 ;
}
2008-10-10 00:24:43 +04:00
int udev_device_get_timeout ( struct udev_device * udev_device )
2008-09-09 16:06:20 +04:00
{
return udev_device - > timeout ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_timeout ( struct udev_device * udev_device , int timeout )
2008-09-09 16:06:20 +04:00
{
udev_device - > timeout = timeout ;
return 0 ;
}
2008-10-10 00:24:43 +04:00
int udev_device_get_event_timeout ( struct udev_device * udev_device )
2008-09-26 21:43:32 +04:00
{
if ( ! udev_device - > info_loaded )
2008-11-05 14:23:06 +03:00
device_load_info ( udev_device ) ;
2008-09-26 21:43:32 +04:00
return udev_device - > event_timeout ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_event_timeout ( struct udev_device * udev_device , int event_timeout )
2008-09-26 21:43:32 +04:00
{
udev_device - > event_timeout = event_timeout ;
return 0 ;
}
2008-09-09 16:06:20 +04:00
2008-10-10 00:24:43 +04:00
int udev_device_set_seqnum ( struct udev_device * udev_device , unsigned long long int seqnum )
2008-09-09 16:37:36 +04:00
{
2008-10-16 13:37:22 +04:00
char num [ 32 ] ;
2008-09-09 16:37:36 +04:00
udev_device - > seqnum = seqnum ;
2008-10-16 13:37:22 +04:00
snprintf ( num , sizeof ( num ) , " %llu " , seqnum ) ;
udev_device_add_property ( udev_device , " SEQNUM " , num ) ;
2008-09-09 16:37:36 +04:00
return 0 ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_devnum ( struct udev_device * udev_device , dev_t devnum )
2008-09-09 16:06:20 +04:00
{
2008-10-16 13:37:22 +04:00
char num [ 32 ] ;
2008-09-09 16:06:20 +04:00
udev_device - > devnum = devnum ;
2008-10-16 13:37:22 +04:00
snprintf ( num , sizeof ( num ) , " %u " , major ( devnum ) ) ;
udev_device_add_property ( udev_device , " MAJOR " , num ) ;
snprintf ( num , sizeof ( num ) , " %u " , minor ( devnum ) ) ;
udev_device_add_property ( udev_device , " MINOR " , num ) ;
2008-09-09 16:06:20 +04:00
return 0 ;
}
2008-09-10 12:09:34 +04:00
2008-10-10 00:24:43 +04:00
int udev_device_get_num_fake_partitions ( 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 )
2008-11-05 14:23:06 +03:00
device_load_info ( udev_device ) ;
2008-09-10 12:09:34 +04:00
return udev_device - > num_fake_partitions ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_num_fake_partitions ( struct udev_device * udev_device , int num )
2008-09-10 12:09:34 +04:00
{
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-10-10 00:24:43 +04:00
int udev_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 )
2008-11-05 14:23:06 +03:00
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-10-10 00:24:43 +04:00
int udev_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
}
2008-10-10 00:24:43 +04:00
int udev_device_get_ignore_remove ( 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 )
2008-11-05 14:23:06 +03:00
device_load_info ( udev_device ) ;
2008-09-10 12:09:34 +04:00
return udev_device - > ignore_remove ;
}
2008-10-10 00:24:43 +04:00
int udev_device_set_ignore_remove ( struct udev_device * udev_device , int ignore )
2008-09-10 12:09:34 +04:00
{
2008-09-10 16:17:36 +04:00
udev_device - > ignore_remove = ignore ;
return 0 ;
2008-09-10 12:09:34 +04:00
}
2009-02-23 20:31:26 +03:00
int udev_device_get_watch_handle ( struct udev_device * udev_device )
{
if ( ! udev_device - > info_loaded )
device_load_info ( udev_device ) ;
return udev_device - > watch_handle ;
}
int udev_device_set_watch_handle ( struct udev_device * udev_device , int handle )
{
udev_device - > watch_handle = handle ;
return 0 ;
}