2008-10-01 11:34:07 +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-10-01 11:34:07 +04:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <stddef.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include <dirent.h>
# include <fcntl.h>
# include <sys/stat.h>
# include "libudev.h"
# include "libudev-private.h"
struct udev_queue {
struct udev * udev ;
int refcount ;
unsigned long long int last_seen_udev_seqnum ;
2008-10-10 00:24:43 +04:00
struct udev_list_node queue_list ;
struct udev_list_node failed_list ;
2008-10-01 11:34:07 +04:00
} ;
struct udev_queue * udev_queue_new ( struct udev * udev )
{
struct udev_queue * udev_queue ;
if ( udev = = NULL )
return NULL ;
2008-10-21 14:10:32 +04:00
udev_queue = calloc ( 1 , sizeof ( struct udev_queue ) ) ;
2008-10-01 11:34:07 +04:00
if ( udev_queue = = NULL )
return NULL ;
udev_queue - > refcount = 1 ;
udev_queue - > udev = udev ;
2008-10-10 00:24:43 +04:00
udev_list_init ( & udev_queue - > queue_list ) ;
udev_list_init ( & udev_queue - > failed_list ) ;
2008-10-01 11:34:07 +04:00
return udev_queue ;
}
struct udev_queue * udev_queue_ref ( struct udev_queue * udev_queue )
{
if ( udev_queue = = NULL )
return NULL ;
udev_queue - > refcount + + ;
return udev_queue ;
}
void udev_queue_unref ( struct udev_queue * udev_queue )
{
if ( udev_queue = = NULL )
return ;
udev_queue - > refcount - - ;
if ( udev_queue - > refcount > 0 )
return ;
2008-10-18 21:27:38 +04:00
udev_list_cleanup_entries ( udev_queue - > udev , & udev_queue - > queue_list ) ;
udev_list_cleanup_entries ( udev_queue - > udev , & udev_queue - > failed_list ) ;
2008-10-01 11:34:07 +04:00
free ( udev_queue ) ;
}
struct udev * udev_queue_get_udev ( struct udev_queue * udev_queue )
{
if ( udev_queue = = NULL )
return NULL ;
return udev_queue - > udev ;
}
unsigned long long int udev_queue_get_kernel_seqnum ( struct udev_queue * udev_queue )
{
char filename [ UTIL_PATH_SIZE ] ;
unsigned long long int seqnum ;
int fd ;
char buf [ 32 ] ;
ssize_t len ;
if ( udev_queue = = NULL )
return - EINVAL ;
util_strlcpy ( filename , udev_get_sys_path ( udev_queue - > udev ) , sizeof ( filename ) ) ;
util_strlcat ( filename , " /kernel/uevent_seqnum " , sizeof ( filename ) ) ;
fd = open ( filename , O_RDONLY ) ;
if ( fd < 0 )
return 0 ;
len = read ( fd , buf , sizeof ( buf ) ) ;
close ( fd ) ;
if ( len < = 2 )
return 0 ;
buf [ len - 1 ] = ' \0 ' ;
seqnum = strtoull ( buf , NULL , 10 ) ;
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " seqnum=%llu \n " , seqnum ) ;
2008-10-01 11:34:07 +04:00
return seqnum ;
}
unsigned long long int udev_queue_get_udev_seqnum ( struct udev_queue * udev_queue )
{
char filename [ UTIL_PATH_SIZE ] ;
unsigned long long int seqnum ;
int fd ;
char buf [ 32 ] ;
ssize_t len ;
if ( udev_queue = = NULL )
return - EINVAL ;
util_strlcpy ( filename , udev_get_dev_path ( udev_queue - > udev ) , sizeof ( filename ) ) ;
util_strlcat ( filename , " /.udev/uevent_seqnum " , sizeof ( filename ) ) ;
fd = open ( filename , O_RDONLY ) ;
if ( fd < 0 )
return 0 ;
len = read ( fd , buf , sizeof ( buf ) ) ;
close ( fd ) ;
if ( len < = 2 )
return 0 ;
buf [ len - 1 ] = ' \0 ' ;
seqnum = strtoull ( buf , NULL , 10 ) ;
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " seqnum=%llu \n " , seqnum ) ;
2008-10-01 11:34:07 +04:00
udev_queue - > last_seen_udev_seqnum = seqnum ;
return seqnum ;
}
2008-11-06 21:41:58 +03:00
int udev_queue_get_udev_is_active ( struct udev_queue * udev_queue )
{
char filename [ UTIL_PATH_SIZE ] ;
struct stat statbuf ;
if ( udev_queue = = NULL )
return 0 ;
util_strlcpy ( filename , udev_get_dev_path ( udev_queue - > udev ) , sizeof ( filename ) ) ;
util_strlcat ( filename , " /.udev/uevent_seqnum " , sizeof ( filename ) ) ;
if ( stat ( filename , & statbuf ) = = 0 )
return 1 ;
return 0 ;
}
2008-10-01 11:34:07 +04:00
int udev_queue_get_queue_is_empty ( struct udev_queue * udev_queue )
{
char queuename [ UTIL_PATH_SIZE ] ;
struct stat statbuf ;
unsigned long long int seqnum_kernel ;
if ( udev_queue = = NULL )
return - EINVAL ;
util_strlcpy ( queuename , udev_get_dev_path ( udev_queue - > udev ) , sizeof ( queuename ) ) ;
util_strlcat ( queuename , " /.udev/queue " , sizeof ( queuename ) ) ;
if ( stat ( queuename , & statbuf ) = = 0 ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " queue is not empty \n " ) ;
2008-10-01 11:34:07 +04:00
return 0 ;
}
seqnum_kernel = udev_queue_get_kernel_seqnum ( udev_queue ) ;
if ( seqnum_kernel < = udev_queue - > last_seen_udev_seqnum ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " queue is empty \n " ) ;
2008-10-01 11:34:07 +04:00
return 1 ;
}
2008-11-06 21:41:58 +03:00
/* update udev seqnum, and check if udev is still running */
if ( udev_queue_get_udev_seqnum ( udev_queue ) = = 0 )
if ( ! udev_queue_get_udev_is_active ( udev_queue ) )
return 1 ;
2008-10-01 11:34:07 +04:00
if ( seqnum_kernel < = udev_queue - > last_seen_udev_seqnum ) {
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " queue is empty \n " ) ;
2008-10-01 11:34:07 +04:00
return 1 ;
}
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " queue is empty, but kernel events still pending [%llu]<->[%llu] \n " ,
2008-10-01 11:34:07 +04:00
seqnum_kernel , udev_queue - > last_seen_udev_seqnum ) ;
return 0 ;
}
int udev_queue_get_seqnum_is_finished ( struct udev_queue * udev_queue , unsigned long long int seqnum )
{
char filename [ UTIL_PATH_SIZE ] ;
struct stat statbuf ;
if ( udev_queue = = NULL )
return - EINVAL ;
2009-04-23 17:16:26 +04:00
/* did it reach the queue? */
2009-04-23 15:23:45 +04:00
if ( seqnum > udev_queue - > last_seen_udev_seqnum )
if ( seqnum > udev_queue_get_udev_seqnum ( udev_queue ) )
2008-10-01 11:34:07 +04:00
return 0 ;
2009-04-23 17:16:26 +04:00
/* is it still in the queue? */
2008-10-01 11:34:07 +04:00
snprintf ( filename , sizeof ( filename ) , " %s/.udev/queue/%llu " ,
udev_get_dev_path ( udev_queue - > udev ) , seqnum ) ;
2009-03-05 01:32:16 +03:00
if ( lstat ( filename , & statbuf ) = = 0 )
2008-10-01 11:34:07 +04:00
return 0 ;
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " seqnum: %llu finished \n " , seqnum ) ;
2008-10-01 11:34:07 +04:00
return 1 ;
}
struct udev_list_entry * udev_queue_get_queued_list_entry ( struct udev_queue * udev_queue )
{
char path [ UTIL_PATH_SIZE ] ;
DIR * dir ;
struct dirent * dent ;
if ( udev_queue = = NULL )
return NULL ;
2008-10-18 21:27:38 +04:00
udev_list_cleanup_entries ( udev_queue - > udev , & udev_queue - > queue_list ) ;
2008-10-01 11:34:07 +04:00
util_strlcpy ( path , udev_get_dev_path ( udev_queue - > udev ) , sizeof ( path ) ) ;
util_strlcat ( path , " /.udev/queue " , sizeof ( path ) ) ;
dir = opendir ( path ) ;
if ( dir = = NULL )
return NULL ;
for ( dent = readdir ( dir ) ; dent ! = NULL ; dent = readdir ( dir ) ) {
char filename [ UTIL_PATH_SIZE ] ;
char syspath [ UTIL_PATH_SIZE ] ;
size_t syslen ;
ssize_t len ;
if ( dent - > d_name [ 0 ] = = ' . ' )
continue ;
util_strlcpy ( filename , path , sizeof ( filename ) ) ;
util_strlcat ( filename , " / " , sizeof ( filename ) ) ;
util_strlcat ( filename , dent - > d_name , sizeof ( filename ) ) ;
syslen = util_strlcpy ( syspath , udev_get_sys_path ( udev_queue - > udev ) , sizeof ( syspath ) ) ;
len = readlink ( filename , & syspath [ syslen ] , sizeof ( syspath ) - syslen ) ;
if ( len < 0 | | len > = ( ssize_t ) ( sizeof ( syspath ) - syslen ) )
continue ;
syspath [ syslen + len ] = ' \0 ' ;
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " found '%s' [%s] \n " , syspath , dent - > d_name ) ;
2008-10-10 00:24:43 +04:00
udev_list_entry_add ( udev_queue - > udev , & udev_queue - > queue_list , syspath , dent - > d_name , 0 , 0 ) ;
2008-10-01 11:34:07 +04:00
}
closedir ( dir ) ;
2008-10-10 00:24:43 +04:00
return udev_list_get_entry ( & udev_queue - > queue_list ) ;
2008-10-01 11:34:07 +04:00
}
struct udev_list_entry * udev_queue_get_failed_list_entry ( struct udev_queue * udev_queue )
{
char path [ UTIL_PATH_SIZE ] ;
DIR * dir ;
struct dirent * dent ;
if ( udev_queue = = NULL )
return NULL ;
2008-10-18 21:27:38 +04:00
udev_list_cleanup_entries ( udev_queue - > udev , & udev_queue - > failed_list ) ;
2008-10-01 11:34:07 +04:00
util_strlcpy ( path , udev_get_dev_path ( udev_queue - > udev ) , sizeof ( path ) ) ;
util_strlcat ( path , " /.udev/failed " , sizeof ( path ) ) ;
dir = opendir ( path ) ;
if ( dir = = NULL )
return NULL ;
for ( dent = readdir ( dir ) ; dent ! = NULL ; dent = readdir ( dir ) ) {
char filename [ UTIL_PATH_SIZE ] ;
char syspath [ UTIL_PATH_SIZE ] ;
struct stat statbuf ;
size_t syslen ;
ssize_t len ;
if ( dent - > d_name [ 0 ] = = ' . ' )
continue ;
util_strlcpy ( filename , path , sizeof ( filename ) ) ;
util_strlcat ( filename , " / " , sizeof ( filename ) ) ;
util_strlcat ( filename , dent - > d_name , sizeof ( filename ) ) ;
syslen = util_strlcpy ( syspath , udev_get_sys_path ( udev_queue - > udev ) , sizeof ( syspath ) ) ;
len = readlink ( filename , & syspath [ syslen ] , sizeof ( syspath ) - syslen ) ;
if ( len < 0 | | len > = ( ssize_t ) ( sizeof ( syspath ) - syslen ) )
continue ;
syspath [ syslen + len ] = ' \0 ' ;
2008-11-01 22:16:24 +03:00
dbg ( udev_queue - > udev , " found '%s' [%s] \n " , syspath , dent - > d_name ) ;
2008-10-01 11:34:07 +04:00
util_strlcpy ( filename , syspath , sizeof ( filename ) ) ;
util_strlcat ( filename , " /uevent " , sizeof ( filename ) ) ;
if ( stat ( filename , & statbuf ) ! = 0 )
continue ;
2008-10-10 00:24:43 +04:00
udev_list_entry_add ( udev_queue - > udev , & udev_queue - > failed_list , syspath , NULL , 0 , 0 ) ;
2008-10-01 11:34:07 +04:00
}
closedir ( dir ) ;
2008-10-10 00:24:43 +04:00
return udev_list_get_entry ( & udev_queue - > failed_list ) ;
2008-10-01 11:34:07 +04:00
}
2008-10-10 00:24:43 +04:00
int udev_queue_export_udev_seqnum ( struct udev_queue * udev_queue , unsigned long long int seqnum )
2008-10-01 11:34:07 +04:00
{
2008-10-10 00:24:43 +04:00
return - 1 ;
2008-10-01 11:34:07 +04:00
}
2009-04-26 15:59:39 +04:00
int udev_queue_export_device_queued ( struct udev_queue * udev_queue , struct udev_device * udev_device )
2008-10-01 11:34:07 +04:00
{
2008-10-10 00:24:43 +04:00
return - 1 ;
2008-10-01 11:34:07 +04:00
}
2009-04-26 15:59:39 +04:00
int udev_queue_export_device_finished ( struct udev_queue * udev_queue , struct udev_device * udev_device )
2008-10-01 11:34:07 +04:00
{
2008-10-10 00:24:43 +04:00
return - 1 ;
2008-10-01 11:34:07 +04:00
}
2009-04-26 15:59:39 +04:00
int udev_queue_export_device_failed ( struct udev_queue * udev_queue , struct udev_device * udev_device )
2008-10-01 11:34:07 +04:00
{
2008-10-10 00:24:43 +04:00
return - 1 ;
2008-10-01 11:34:07 +04:00
}