2008-08-28 00:02:41 +04:00
/*
* libudev - interface to udev device information
*
2009-05-20 19:57:52 +04:00
* Copyright ( C ) 2008 - 2009 Kay Sievers < kay . sievers @ vrfy . org >
2008-08-28 00:02:41 +04:00
*
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"
2009-06-15 19:09:43 +04:00
/**
* SECTION : libudev - device
* @ short_description : kernel sys devices
*
* Representation of kernel sys devices . Devices are uniquely identified
* by their syspath , every device has exactly one path in the kernel sys
* filesystem . Devices usually belong to a kernel subsystem , and and have
* a unique name inside that subsytem .
*/
2009-06-15 15:22:38 +04:00
/**
* udev_device :
*
2009-06-15 19:09:43 +04:00
* Opaque object representing one kernel sys device .
2009-06-15 15:22:38 +04:00
*/
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 ;
2009-05-04 06:52:31 +04:00
char * knodename ;
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
{
2009-05-20 19:57:52 +04:00
char * s ;
size_t l ;
2008-09-10 16:17:36 +04:00
2009-05-20 19:57:52 +04:00
s = filename ;
l = util_strpcpyl ( & s , len , udev_get_dev_path ( udev ) , " /.udev/db/ " , NULL ) ;
2009-05-21 03:44:45 +04:00
return util_path_encode ( devpath , s , l ) ;
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 ] ;
}
2009-05-20 19:57:52 +04:00
util_strscpyl ( devnode , sizeof ( devnode ) , udev_get_dev_path ( udev_device - > udev ) , " / " , target , NULL ) ;
2008-10-14 21:53:47 +04:00
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 ] ;
}
2009-05-20 19:57:52 +04:00
util_strscpyl ( devlink , sizeof ( devlink ) , udev_get_dev_path ( udev_device - > udev ) , " / " , lnk , NULL ) ;
2008-10-14 21:53:47 +04:00
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 ' :
2009-05-20 19:57:52 +04:00
util_strscpyl ( filename , sizeof ( filename ) , udev_get_dev_path ( udev_device - > udev ) , " / " , val , NULL ) ;
2008-10-14 21:53:47 +04:00
udev_device_set_devnode ( udev_device , filename ) ;
2008-09-10 16:17:36 +04:00
break ;
case ' S ' :
2009-05-20 19:57:52 +04:00
util_strscpyl ( filename , sizeof ( filename ) , udev_get_dev_path ( udev_device - > udev ) , " / " , val , NULL ) ;
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 ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( filename , sizeof ( filename ) , udev_device - > syspath , " /uevent " , NULL ) ;
2008-09-26 21:43:32 +04:00
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 ) ;
2009-05-04 06:52:31 +04:00
else if ( strncmp ( line , " DEVNAME= " , 8 ) = = 0 )
udev_device_set_knodename ( udev_device , & line [ 8 ] ) ;
2008-09-26 21:43:32 +04:00
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 ;
}
2009-06-09 15:11:23 +04:00
struct udev_device * udev_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 */
2009-05-20 19:57:52 +04:00
util_strscpy ( path , sizeof ( path ) , syspath ) ;
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 ] ;
2009-05-20 19:57:52 +04:00
util_strscpy ( block , sizeof ( block ) , path ) ;
2008-10-01 12:22:47 +04:00
pos = strrchr ( block , ' / ' ) ;
if ( pos = = NULL )
return NULL ;
2009-05-20 19:57:52 +04:00
util_strscpy ( part , sizeof ( part ) , pos ) ;
2008-10-01 12:22:47 +04:00
pos [ 0 ] = ' \0 ' ;
2009-05-20 19:57:52 +04:00
if ( util_resolve_sys_link ( udev , block , sizeof ( block ) ) = = 0 )
util_strscpyl ( path , sizeof ( path ) , block , part , NULL ) ;
2008-10-01 12:22:47 +04:00
}
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 */
2009-05-20 19:57:52 +04:00
util_strscpyl ( file , sizeof ( file ) , path , " /uevent " , NULL ) ;
2008-09-28 05:34:57 +04:00
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 ;
}
}
2009-06-09 15:11:23 +04:00
udev_device = udev_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 ;
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_new_from_devnum :
* @ udev : udev library context
* @ type : char or block device
* @ devnum : device major / minor number
*
* Create new udev device , and fill in information from the sys
* device and the udev database entry . The device is looked up
* by its major / minor number . Character and block device numbers
* are not unique across the two types , they do not share the same
* range of numbers .
*
* The initial refcount is 1 , and needs to be decremented to
* release the resources of the udev device .
*
* Returns : a new udev device , or # NULL , if it does not exist
* */
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
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_new_from_subsystem_sysname :
* @ udev : udev library context
* @ subsystem : the subsytem of the device
* @ sysname : the name of the device
*
* Create new udev device , and fill in information from the sys
* device and the udev database entry . The device is looked up
* by the subsytem and name string of the device , like " mem " ,
* " zero " , or " block " , " sda " .
*
* The initial refcount is 1 , and needs to be decremented to
* release the resources of the udev device .
*
* Returns : a new udev device , or # NULL , if it does not exist
* */
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 )
{
char path_full [ UTIL_PATH_SIZE ] ;
char * path ;
2009-05-20 19:57:52 +04:00
size_t l ;
2008-10-07 22:20:34 +04:00
struct stat statbuf ;
2009-05-20 19:57:52 +04:00
path = path_full ;
l = util_strpcpyl ( & path , sizeof ( path_full ) , udev_get_sys_path ( udev ) , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( strcmp ( subsystem , " subsystem " ) = = 0 ) {
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /subsystem/ " , sysname , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /bus/ " , sysname , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /class/ " , sysname , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
goto out ;
}
if ( strcmp ( subsystem , " module " ) = = 0 ) {
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /module/ " , sysname , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
goto out ;
}
if ( strcmp ( subsystem , " drivers " ) = = 0 ) {
char subsys [ UTIL_NAME_SIZE ] ;
char * driver ;
2009-05-20 19:57:52 +04:00
util_strscpy ( subsys , sizeof ( subsys ) , sysname ) ;
2008-10-07 22:20:34 +04:00
driver = strchr ( subsys , ' : ' ) ;
if ( driver ! = NULL ) {
driver [ 0 ] = ' \0 ' ;
driver = & driver [ 1 ] ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /subsystem/ " , subsys , " /drivers/ " , driver , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /bus/ " , subsys , " /drivers/ " , driver , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
}
goto out ;
}
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /subsystem/ " , subsystem , " /devices/ " , sysname , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /bus/ " , subsystem , " /devices/ " , sysname , NULL ) ;
2008-10-07 22:20:34 +04:00
if ( stat ( path_full , & statbuf ) = = 0 )
goto found ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , l , " /class/ " , subsystem , " / " , sysname , NULL ) ;
2008-10-07 22:20:34 +04:00
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 ) {
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , sizeof ( path ) , udev_device - > syspath , " /device " , NULL ) ;
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
2009-05-20 19:57:52 +04:00
util_strscpy ( path , sizeof ( path ) , udev_device - > syspath ) ;
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
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_parent :
* @ udev_device : the device to start searching from
*
* Find the next parent device , and fill in information from the sys
* device and the udev database entry .
*
* The returned the device is not referenced . It is attached to the
* child device , and will be cleaned up when the child device
* is cleaned up .
*
* It is not neccessarily just the upper level directory , empty or not
* recognized sys directories are ignored .
*
* It can be called as many times as needed , without caring about
* references .
*
* Returns : a new udev device , or # NULL , if it no parent exist .
* */
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-06-15 15:22:38 +04:00
/**
* udev_device_get_parent_with_subsystem_devtype :
* @ udev_device : udev device to start searching from
* @ subsystem : the subsytem of the device
* @ devtype : the type ( DEVTYPE ) of the device
*
* Find the next parent device , with a matching subsystem and devtype
* value , and fill in information from the sys device and the udev
* database entry .
*
* The returned the device is not referenced . It is attached to the
* child device , and will be cleaned up when the child device
* is cleaned up .
*
* It can be called as many times as needed , without caring about
* references .
*
2009-06-15 22:28:28 +04:00
* Returns : a new udev device , or # NULL if no matching parent exists .
2009-06-15 15:22:38 +04:00
* */
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 ) ;
2009-05-04 06:52:31 +04:00
free ( udev_device - > knodename ) ;
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 ;
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_sysname :
* @ udev_device : udev device
*
* Returns : the sys name of the device device
* */
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 ;
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_sysnum :
* @ udev_device : udev device
*
* Returns : the trailing number of of the device name
* */
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 ) {
2009-05-20 19:57:52 +04:00
char * s ;
size_t l ;
s = symlinks ;
l = util_strpcpyl ( & s , sizeof ( symlinks ) , udev_list_entry_get_name ( list_entry ) , NULL ) ;
udev_list_entry_foreach ( list_entry , udev_list_entry_get_next ( list_entry ) )
l = util_strpcpyl ( & s , l , " " , udev_list_entry_get_name ( list_entry ) , NULL ) ;
2008-10-15 18:56:06 +04:00
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
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_driver :
* @ udev_device : udev device
*
2009-06-15 19:09:43 +04:00
* Returns : the driver string , or # NULL if there is no driver attached .
2009-06-15 15:22:38 +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 ;
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_devnum :
* @ udev_device : udev device
*
* Returns : the device major / minor number .
* */
2008-09-09 16:06:20 +04:00
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 ;
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_action :
* @ udev_device : udev device
*
* This is only valid if the device was received through a monitor . Devices read from
* sys do not have an action string . Usual actions are : add , remove , change , online ,
* offline .
*
* Returns : the kernel action value , or # NULL if there is no action value available .
* */
2008-09-09 16:06:20 +04:00
const char * udev_device_get_action ( struct udev_device * udev_device )
{
if ( udev_device = = NULL )
return NULL ;
return udev_device - > action ;
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_devnum :
* @ udev_device : udev device
*
* This is only valid if the device was received through a monitor . Devices read from
* sys do not have a sequence number .
*
* Returns : the kernel event sequence number , or 0 if there is no sequence number available .
* */
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 ;
}
2009-06-15 15:22:38 +04:00
/**
* udev_device_get_sysattr_value :
* @ udev_device : udev device
* @ sysattr : attribute name
*
2009-07-03 00:56:19 +04:00
* The retrieved value is cached in the device . Repeated calls will return the same
2009-06-15 15:22:38 +04:00
* value and not open the attribute again .
*
* Returns : the content of a sys attribute file , or # NULL if there is no sys attribute value .
* */
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
}
}
2009-05-20 19:57:52 +04:00
util_strscpyl ( path , sizeof ( path ) , udev_device_get_syspath ( udev_device ) , " / " , sysattr , NULL ) ;
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 ;
2009-05-20 19:57:52 +04:00
util_strscpy ( name , sizeof ( name ) , property ) ;
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-06-15 15:22:38 +04:00
/**
* udev_device_get_property_value :
* @ udev_device : udev device
* @ key : property name
*
* Returns : the value of a device property , or # NULL if there is no such property .
* */
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
struct udev_list_entry * list_entry ;
2009-05-20 19:57:52 +04:00
char * s ;
size_t l ;
2008-10-26 05:39:41 +03:00
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
i = 0 ;
2009-05-20 19:57:52 +04:00
s = udev_device - > monitor_buf ;
l = MONITOR_BUF_SIZE ;
2008-10-26 05:39:41 +03:00
udev_list_entry_foreach ( list_entry , udev_device_get_properties_list_entry ( udev_device ) ) {
2009-06-28 04:21:58 +04:00
const char * key ;
key = udev_list_entry_get_name ( list_entry ) ;
/* skip private variables */
if ( key [ 0 ] = = ' . ' )
continue ;
2008-10-26 05:39:41 +03:00
/* add string to envp array */
2009-05-20 19:57:52 +04:00
udev_device - > envp [ i + + ] = s ;
2008-10-26 05:39:41 +03:00
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 */
2009-06-28 04:21:58 +04:00
l = util_strpcpyl ( & s , l , key , " = " , udev_list_entry_get_value ( list_entry ) , NULL ) ;
2009-05-20 19:57:52 +04:00
if ( l = = 0 )
2008-10-24 18:36:27 +04:00
return - EINVAL ;
2009-05-20 19:57:52 +04:00
s + + ;
2008-10-24 18:36:27 +04:00
}
2008-10-26 05:39:41 +03:00
udev_device - > envp [ i ] = NULL ;
2009-05-20 19:57:52 +04:00
udev_device - > monitor_buf_len = s - udev_device - > monitor_buf ;
2008-10-26 05:39:41 +03:00
udev_device - > envp_uptodate = 1 ;
2009-05-20 19:57:52 +04:00
dbg ( udev_device - > udev , " filled envp/monitor buffer, %u properties, %zu bytes \n " ,
i , udev_device - > monitor_buf_len ) ;
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
{
2009-07-08 04:02:40 +04:00
free ( udev_device - > 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 ;
}
2009-05-04 06:52:31 +04:00
const char * udev_device_get_knodename ( struct udev_device * udev_device )
{
return udev_device - > knodename ;
}
int udev_device_set_knodename ( struct udev_device * udev_device , const char * knodename )
{
2009-07-08 04:02:40 +04:00
free ( udev_device - > knodename ) ;
2009-05-04 06:52:31 +04:00
udev_device - > knodename = strdup ( knodename ) ;
if ( udev_device - > knodename = = NULL )
return - ENOMEM ;
2009-07-03 20:40:38 +04:00
udev_device_add_property ( udev_device , " DEVNAME " , udev_device - > knodename ) ;
2009-05-04 06:52:31 +04:00
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 ;
}