2007-01-08 18:18:52 +03:00
/*
2005-12-02 18:39:16 +03:00
* Copyright ( C ) 2005 Red Hat , Inc . All rights reserved .
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "lib.h"
# include "libdevmapper-event.h"
//#include "libmultilog.h"
# include "dmeventd.h"
# include <errno.h>
# include <fcntl.h>
# include <stdio.h>
# include <stdint.h>
# include <stdlib.h>
# include <string.h>
# include <sys/file.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <sys/wait.h>
2007-01-12 00:54:53 +03:00
# include <arpa/inet.h> /* for htonl, ntohl */
struct dm_event_handler {
const char * dso ;
2007-01-15 21:21:01 +03:00
const char * devname ;
2007-01-12 00:54:53 +03:00
const char * uuid ;
int major ;
int minor ;
2007-01-15 21:21:01 +03:00
enum dm_event_mask mask ;
2007-01-12 00:54:53 +03:00
} ;
2007-01-15 21:21:01 +03:00
static void dm_event_handler_clear_devname ( struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
dmevh - > devname = dmevh - > uuid = NULL ;
dmevh - > major = dmevh - > minor = 0 ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-12 00:54:53 +03:00
struct dm_event_handler * dm_event_handler_create ( void )
{
2007-01-15 21:21:01 +03:00
struct dm_event_handler * dmevh = NULL ;
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
if ( ! ( dmevh = dm_malloc ( sizeof ( * dmevh ) ) ) )
2007-01-12 00:54:53 +03:00
return NULL ;
2007-01-15 21:21:01 +03:00
dmevh - > dso = dmevh - > devname = dmevh - > uuid = NULL ;
dmevh - > major = dmevh - > minor = 0 ;
dmevh - > mask = 0 ;
2007-01-12 00:54:53 +03:00
2007-01-15 21:21:01 +03:00
return dmevh ;
2007-01-12 00:54:53 +03:00
}
2007-01-15 21:21:01 +03:00
void dm_event_handler_destroy ( struct dm_event_handler * dmevh )
2005-12-02 18:39:16 +03:00
{
2007-01-15 21:21:01 +03:00
dm_free ( dmevh ) ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
void dm_event_handler_set_dso ( struct dm_event_handler * dmevh , const char * path )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
dmevh - > dso = path ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
void dm_event_handler_set_devname ( struct dm_event_handler * dmevh , const char * devname )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
dm_event_handler_clear_devname ( dmevh ) ;
dmevh - > devname = devname ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
void dm_event_handler_set_uuid ( struct dm_event_handler * dmevh , const char * uuid )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
dm_event_handler_clear_devname ( dmevh ) ;
dmevh - > uuid = uuid ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
void dm_event_handler_set_major ( struct dm_event_handler * dmevh , int major )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
int minor = dmevh - > minor ;
2007-01-12 00:54:53 +03:00
2007-01-15 21:21:01 +03:00
dm_event_handler_clear_devname ( dmevh ) ;
dmevh - > major = major ;
dmevh - > minor = minor ;
2005-12-02 18:39:16 +03:00
}
2007-01-15 21:21:01 +03:00
void dm_event_handler_set_minor ( struct dm_event_handler * dmevh , int minor )
2005-12-02 18:39:16 +03:00
{
2007-01-15 21:21:01 +03:00
int major = dmevh - > major ;
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
dm_event_handler_clear_devname ( dmevh ) ;
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
dmevh - > major = major ;
dmevh - > minor = minor ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
void dm_event_handler_set_event_mask ( struct dm_event_handler * dmevh ,
enum dm_event_mask evmask )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
dmevh - > mask = evmask ;
2007-01-12 00:54:53 +03:00
}
2007-01-15 21:21:01 +03:00
const char * dm_event_handler_get_dso ( const struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
return dmevh - > dso ;
2007-01-12 00:54:53 +03:00
}
2007-01-15 21:21:01 +03:00
const char * dm_event_handler_get_devname ( const struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
return dmevh - > devname ;
2007-01-12 00:54:53 +03:00
}
2007-01-15 21:21:01 +03:00
const char * dm_event_handler_get_uuid ( const struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
return dmevh - > uuid ;
2007-01-12 00:54:53 +03:00
}
2007-01-15 21:21:01 +03:00
int dm_event_handler_get_major ( const struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
return dmevh - > major ;
2007-01-12 00:54:53 +03:00
}
2007-01-15 21:21:01 +03:00
int dm_event_handler_get_minor ( const struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
return dmevh - > minor ;
2007-01-12 00:54:53 +03:00
}
2007-01-15 21:21:01 +03:00
enum dm_event_mask dm_event_handler_get_event_mask ( const struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-15 21:21:01 +03:00
return dmevh - > mask ;
2005-12-02 18:39:16 +03:00
}
2005-12-20 01:56:47 +03:00
/*
* daemon_read
* @ fifos
* @ msg
*
* Read message from daemon .
*
* Returns : 0 on failure , 1 on success
*/
2007-01-15 21:21:01 +03:00
static int _daemon_read ( struct dm_event_fifos * fifos ,
struct dm_event_daemon_message * msg )
2005-12-02 18:39:16 +03:00
{
2006-01-31 17:50:38 +03:00
unsigned bytes = 0 ;
2007-01-08 18:18:52 +03:00
int ret , i ;
2005-12-02 18:39:16 +03:00
fd_set fds ;
2007-01-12 00:54:53 +03:00
struct timeval tval = { 0 , 0 } ;
size_t size = 2 * sizeof ( uint32_t ) ; /* status + size */
2007-01-08 18:18:52 +03:00
char * buf = alloca ( size ) ;
int header = 1 ;
2005-12-02 18:39:16 +03:00
2007-01-08 18:18:52 +03:00
while ( bytes < size ) {
for ( i = 0 , ret = 0 ; ( i < 20 ) & & ( ret < 1 ) ; i + + ) {
2005-12-02 18:39:16 +03:00
/* Watch daemon read FIFO for input. */
FD_ZERO ( & fds ) ;
FD_SET ( fifos - > server , & fds ) ;
2007-01-08 18:18:52 +03:00
tval . tv_sec = 1 ;
2007-01-12 00:54:53 +03:00
ret = select ( fifos - > server + 1 , & fds , NULL , NULL ,
& tval ) ;
2005-12-20 01:56:47 +03:00
if ( ret < 0 & & errno ! = EINTR ) {
2007-01-08 18:18:52 +03:00
log_error ( " Unable to read from event server " ) ;
2005-12-20 01:56:47 +03:00
return 0 ;
}
2007-01-08 18:18:52 +03:00
}
if ( ret < 1 ) {
log_error ( " Unable to read from event server. " ) ;
return 0 ;
}
2005-12-02 18:39:16 +03:00
2007-01-08 18:18:52 +03:00
ret = read ( fifos - > server , buf + bytes , size ) ;
2005-12-20 01:56:47 +03:00
if ( ret < 0 ) {
if ( ( errno = = EINTR ) | | ( errno = = EAGAIN ) )
continue ;
else {
2007-01-08 18:18:52 +03:00
log_error ( " Unable to read from event server. " ) ;
2005-12-20 01:56:47 +03:00
return 0 ;
}
}
bytes + = ret ;
2007-01-12 00:54:53 +03:00
if ( bytes = = 2 * sizeof ( uint32_t ) & & header ) {
2007-01-08 18:18:52 +03:00
msg - > cmd = ntohl ( * ( ( uint32_t * ) buf ) ) ;
msg - > size = ntohl ( * ( ( uint32_t * ) buf + 1 ) ) ;
buf = msg - > data = dm_malloc ( msg - > size ) ;
size = msg - > size ;
bytes = 0 ;
header = 0 ;
}
2005-12-02 18:39:16 +03:00
}
2007-01-08 18:18:52 +03:00
if ( bytes ! = size ) {
if ( msg - > data )
dm_free ( msg - > data ) ;
msg - > data = NULL ;
}
return bytes = = size ;
2005-12-02 18:39:16 +03:00
}
/* Write message to daemon. */
2007-01-15 21:21:01 +03:00
static int _daemon_write ( struct dm_event_fifos * fifos ,
struct dm_event_daemon_message * msg )
2005-12-02 18:39:16 +03:00
{
2006-01-31 17:50:38 +03:00
unsigned bytes = 0 ;
int ret = 0 ;
2005-12-02 18:39:16 +03:00
fd_set fds ;
2007-01-12 00:54:53 +03:00
size_t size = 2 * sizeof ( uint32_t ) + msg - > size ;
2007-01-08 18:18:52 +03:00
char * buf = alloca ( size ) ;
* ( ( uint32_t * ) buf ) = htonl ( msg - > cmd ) ;
* ( ( uint32_t * ) buf + 1 ) = htonl ( msg - > size ) ;
2007-01-12 00:54:53 +03:00
memcpy ( buf + 2 * sizeof ( uint32_t ) , msg - > data , msg - > size ) ;
2007-01-08 18:18:52 +03:00
while ( bytes < size ) {
2005-12-02 18:39:16 +03:00
do {
/* Watch daemon write FIFO to be ready for output. */
FD_ZERO ( & fds ) ;
FD_SET ( fifos - > client , & fds ) ;
2007-01-12 00:54:53 +03:00
ret = select ( fifos - > client + 1 , NULL , & fds , NULL , NULL ) ;
2005-12-20 01:56:47 +03:00
if ( ( ret < 0 ) & & ( errno ! = EINTR ) ) {
2007-01-08 18:18:52 +03:00
log_error ( " Unable to talk to event daemon " ) ;
2005-12-20 01:56:47 +03:00
return 0 ;
}
} while ( ret < 1 ) ;
2005-12-02 18:39:16 +03:00
2007-01-12 00:54:53 +03:00
ret = write ( fifos - > client , ( ( char * ) buf ) + bytes ,
size - bytes ) ;
2005-12-20 01:56:47 +03:00
if ( ret < 0 ) {
if ( ( errno = = EINTR ) | | ( errno = = EAGAIN ) )
continue ;
else {
2007-01-08 18:18:52 +03:00
log_error ( " Unable to talk to event daemon " ) ;
2005-12-20 01:56:47 +03:00
return 0 ;
}
}
bytes + = ret ;
2005-12-02 18:39:16 +03:00
}
2007-01-08 18:18:52 +03:00
return bytes = = size ;
2005-12-02 18:39:16 +03:00
}
2007-01-15 21:21:01 +03:00
static int _daemon_talk ( struct dm_event_fifos * fifos ,
struct dm_event_daemon_message * msg , int cmd ,
const char * dso_name , const char * devname ,
enum dm_event_mask evmask , uint32_t timeout )
2005-12-02 18:39:16 +03:00
{
2007-01-08 18:18:52 +03:00
const char * dso = dso_name ? dso_name : " " ;
2007-01-15 21:21:01 +03:00
const char * dev = devname ? devname : " " ;
2007-01-12 00:54:53 +03:00
const char * fmt = " %s %s %u % " PRIu32 ;
2005-12-02 18:39:16 +03:00
memset ( msg , 0 , sizeof ( * msg ) ) ;
/*
* Set command and pack the arguments
* into ASCII message string .
*/
2007-01-08 18:18:52 +03:00
msg - > cmd = cmd ;
2007-01-15 21:21:01 +03:00
if ( ( msg - > size = dm_asprintf ( & ( msg - > data ) , fmt , dso , dev , evmask ,
timeout ) ) < 0 ) {
log_error ( " _daemon_talk: message allocation failed " ) ;
}
2005-12-02 18:39:16 +03:00
/*
* Write command and message to and
* read status return code from daemon .
*/
2007-01-15 21:21:01 +03:00
if ( ! _daemon_write ( fifos , msg ) ) {
2005-12-02 18:39:16 +03:00
stack ;
return - EIO ;
}
2007-01-15 21:21:01 +03:00
if ( ! _daemon_read ( fifos , msg ) ) {
2005-12-02 18:39:16 +03:00
stack ;
return - EIO ;
}
2007-01-08 18:18:52 +03:00
return ( int32_t ) msg - > cmd ;
2005-12-02 18:39:16 +03:00
}
/*
* start_daemon
*
* This function forks off a process ( dmeventd ) that will handle
2007-01-08 18:18:52 +03:00
* the events . I am currently test opening one of the fifos to
* ensure that the daemon is running and listening . . . I thought
* this would be less expensive than fork / exec ' ing every time .
* Perhaps there is an even quicker / better way ( no , checking the
* lock file is _not_ a better way ) .
2005-12-02 18:39:16 +03:00
*
* Returns : 1 on success , 0 otherwise
*/
2007-01-15 21:21:01 +03:00
static int _start_daemon ( struct dm_event_fifos * fifos )
2005-12-02 18:39:16 +03:00
{
2007-01-08 18:18:52 +03:00
int pid , ret = 0 ;
int status ;
struct stat statbuf ;
if ( stat ( fifos - > client_path , & statbuf ) )
goto start_server ;
if ( ! S_ISFIFO ( statbuf . st_mode ) ) {
log_error ( " %s is not a fifo. " , fifos - > client_path ) ;
2005-12-02 18:39:16 +03:00
return 0 ;
}
2007-01-08 18:18:52 +03:00
/* Anyone listening? If not, errno will be ENXIO */
fifos - > client = open ( fifos - > client_path , O_WRONLY | O_NONBLOCK ) ;
if ( fifos - > client > = 0 ) {
/* server is running and listening */
close ( fifos - > client ) ;
return 1 ;
} else if ( errno ! = ENXIO ) {
/* problem */
log_error ( " %s: Can't open client fifo %s: %s " ,
__func__ , fifos - > client_path , strerror ( errno ) ) ;
stack ;
return 0 ;
2006-01-27 23:45:17 +03:00
}
2007-01-08 18:18:52 +03:00
2007-01-12 00:54:53 +03:00
start_server :
2007-01-08 18:18:52 +03:00
/* server is not running */
2005-12-02 18:39:16 +03:00
pid = fork ( ) ;
if ( pid < 0 )
2007-01-08 18:18:52 +03:00
log_error ( " Unable to fork. " ) ;
2005-12-02 18:39:16 +03:00
2007-01-08 18:18:52 +03:00
else if ( ! pid ) {
2007-01-15 22:11:58 +03:00
execvp ( DMEVENTD_PATH , NULL ) ;
2005-12-02 18:39:16 +03:00
exit ( EXIT_FAILURE ) ;
2007-01-08 18:18:52 +03:00
} else {
if ( waitpid ( pid , & status , 0 ) < 0 )
2007-01-12 00:54:53 +03:00
log_error ( " Unable to start dmeventd: %s " ,
strerror ( errno ) ) ;
2007-01-08 18:18:52 +03:00
else if ( WEXITSTATUS ( status ) )
log_error ( " Unable to start dmeventd. " ) ;
else
ret = 1 ;
2005-12-02 18:39:16 +03:00
}
2005-12-20 01:56:47 +03:00
return ret ;
2005-12-02 18:39:16 +03:00
}
/* Initialize client. */
2007-01-15 21:21:01 +03:00
static int _init_client ( struct dm_event_fifos * fifos )
2005-12-02 18:39:16 +03:00
{
2007-01-12 00:54:53 +03:00
/* FIXME? Is fifo the most suitable method? Why not share
comms / daemon code with something else e . g . multipath ? */
2005-12-02 18:39:16 +03:00
/* init fifos */
memset ( fifos , 0 , sizeof ( * fifos ) ) ;
2005-12-20 01:56:47 +03:00
fifos - > client_path = DM_EVENT_FIFO_CLIENT ;
fifos - > server_path = DM_EVENT_FIFO_SERVER ;
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
if ( ! _start_daemon ( fifos ) ) {
2007-01-08 18:18:52 +03:00
stack ;
2005-12-02 18:39:16 +03:00
return 0 ;
}
2007-01-08 18:18:52 +03:00
/* Open the fifo used to read from the daemon. */
2005-12-02 18:39:16 +03:00
if ( ( fifos - > server = open ( fifos - > server_path , O_RDWR ) ) < 0 ) {
2007-01-08 18:18:52 +03:00
log_error ( " %s: open server fifo %s " ,
2007-01-12 00:54:53 +03:00
__func__ , fifos - > server_path ) ;
2005-12-02 18:39:16 +03:00
stack ;
return 0 ;
}
/* Lock out anyone else trying to do communication with the daemon. */
2007-01-12 00:54:53 +03:00
if ( flock ( fifos - > server , LOCK_EX ) < 0 ) {
2007-01-08 18:18:52 +03:00
log_error ( " %s: flock %s " , __func__ , fifos - > server_path ) ;
2005-12-02 18:39:16 +03:00
close ( fifos - > server ) ;
return 0 ;
}
2007-01-12 00:54:53 +03:00
/* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
2007-01-08 18:18:52 +03:00
if ( ( fifos - > client = open ( fifos - > client_path , O_RDWR | O_NONBLOCK ) ) < 0 ) {
log_error ( " %s: Can't open client fifo %s: %s " ,
__func__ , fifos - > client_path , strerror ( errno ) ) ;
close ( fifos - > server ) ;
stack ;
return 0 ;
2005-12-02 18:39:16 +03:00
}
2007-01-12 00:54:53 +03:00
2005-12-02 18:39:16 +03:00
return 1 ;
}
2007-01-15 21:21:01 +03:00
static void _dtr_client ( struct dm_event_fifos * fifos )
2005-12-02 18:39:16 +03:00
{
if ( flock ( fifos - > server , LOCK_UN ) )
2007-01-08 18:18:52 +03:00
log_error ( " flock unlock %s " , fifos - > server_path ) ;
2005-12-02 18:39:16 +03:00
close ( fifos - > client ) ;
close ( fifos - > server ) ;
}
2007-01-15 21:21:01 +03:00
/* Get uuid of a device */
static struct dm_task * _get_device_info ( const struct dm_event_handler * dmevh )
2005-12-02 18:39:16 +03:00
{
2007-01-15 21:21:01 +03:00
struct dm_task * dmt ;
struct dm_info info ;
2007-01-12 00:54:53 +03:00
2007-01-15 21:21:01 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_INFO ) ) ) {
log_error ( " _get_device_info: dm_task creation for info failed " ) ;
2007-01-12 00:54:53 +03:00
return NULL ;
2007-01-15 21:21:01 +03:00
}
2007-01-12 00:54:53 +03:00
2007-01-15 21:21:01 +03:00
if ( dmevh - > uuid )
dm_task_set_uuid ( dmt , dmevh - > uuid ) ;
else if ( dmevh - > devname )
dm_task_set_name ( dmt , dmevh - > devname ) ;
else if ( dmevh - > major & & dmevh - > minor ) {
dm_task_set_major ( dmt , dmevh - > major ) ;
dm_task_set_minor ( dmt , dmevh - > minor ) ;
/* FIXME Add name or uuid or devno to messages */
if ( ! dm_task_run ( dmt ) ) {
log_error ( " _get_device_info: dm_task_run() failed " ) ;
goto failed ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
if ( ! dm_task_get_info ( dmt , & info ) )
log_error ( " _get_device_info: failed to get info for device " ) ;
goto failed ;
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
if ( ! info . exists ) {
log_error ( " _get_device_info: device not found " ) ;
goto failed ;
}
return dmt ;
failed :
dm_task_destroy ( dmt ) ;
return NULL ;
2005-12-02 18:39:16 +03:00
}
/* Handle the event (de)registration call and return negative error codes. */
2007-01-15 21:21:01 +03:00
static int _do_event ( int cmd , struct dm_event_daemon_message * msg ,
const char * dso_name , const char * devname ,
enum dm_event_mask evmask , uint32_t timeout )
2005-12-02 18:39:16 +03:00
{
int ret ;
struct dm_event_fifos fifos ;
2007-01-15 21:21:01 +03:00
if ( ! _init_client ( & fifos ) ) {
2005-12-02 18:39:16 +03:00
stack ;
return - ESRCH ;
}
2007-01-15 21:21:01 +03:00
ret = _daemon_talk ( & fifos , msg , cmd , dso_name , devname , evmask , timeout ) ;
2005-12-02 18:39:16 +03:00
/* what is the opposite of init? */
2007-01-15 21:21:01 +03:00
_dtr_client ( & fifos ) ;
2007-01-12 00:54:53 +03:00
2005-12-02 18:39:16 +03:00
return ret ;
}
/* External library interface. */
2007-01-15 21:21:01 +03:00
int dm_event_register_handler ( const struct dm_event_handler * dmevh )
2005-12-02 18:39:16 +03:00
{
2007-01-15 21:21:01 +03:00
int ret = 1 , err ;
2007-01-12 00:54:53 +03:00
const char * uuid ;
struct dm_task * dmt ;
2005-12-02 18:39:16 +03:00
struct dm_event_daemon_message msg ;
2007-01-15 21:21:01 +03:00
if ( ! ( dmt = _get_device_info ( dmevh ) ) ) {
stack ;
2006-01-27 23:01:45 +03:00
return 0 ;
}
2005-12-02 18:39:16 +03:00
2007-01-12 00:54:53 +03:00
uuid = dm_task_get_uuid ( dmt ) ;
2007-01-15 21:21:01 +03:00
if ( ( err = _do_event ( DM_EVENT_CMD_REGISTER_FOR_EVENT , & msg ,
dmevh - > dso , uuid , dmevh - > mask , 0 ) ) < 0 ) {
2007-01-12 00:54:53 +03:00
log_error ( " %s: event registration failed: %s " ,
dm_task_get_name ( dmt ) ,
2007-01-08 18:18:52 +03:00
msg . data ? msg . data : strerror ( - err ) ) ;
ret = 0 ;
2007-01-15 21:21:01 +03:00
}
2006-01-27 23:01:45 +03:00
2007-01-08 18:18:52 +03:00
if ( msg . data )
dm_free ( msg . data ) ;
2007-01-12 00:54:53 +03:00
dm_task_destroy ( dmt ) ;
2007-01-08 18:18:52 +03:00
return ret ;
2005-12-02 18:39:16 +03:00
}
2007-01-15 21:21:01 +03:00
int dm_event_unregister_handler ( const struct dm_event_handler * dmevh )
2005-12-02 18:39:16 +03:00
{
2007-01-15 21:21:01 +03:00
int ret = 1 , err ;
2007-01-12 00:54:53 +03:00
const char * uuid ;
struct dm_task * dmt ;
2005-12-02 18:39:16 +03:00
struct dm_event_daemon_message msg ;
2007-01-15 21:21:01 +03:00
if ( ! ( dmt = _get_device_info ( dmevh ) ) ) {
stack ;
2006-01-27 23:01:45 +03:00
return 0 ;
}
2005-12-02 18:39:16 +03:00
2007-01-12 00:54:53 +03:00
uuid = dm_task_get_uuid ( dmt ) ;
2007-01-15 21:21:01 +03:00
if ( ( err = _do_event ( DM_EVENT_CMD_UNREGISTER_FOR_EVENT , & msg ,
dmevh - > dso , uuid , dmevh - > mask , 0 ) ) < 0 ) {
2007-01-12 00:54:53 +03:00
log_error ( " %s: event deregistration failed: %s " ,
dm_task_get_name ( dmt ) ,
2007-01-08 18:18:52 +03:00
msg . data ? msg . data : strerror ( - err ) ) ;
ret = 0 ;
2007-01-15 21:21:01 +03:00
}
2006-01-27 23:01:45 +03:00
2007-01-08 18:18:52 +03:00
if ( msg . data )
dm_free ( msg . data ) ;
2007-01-12 00:54:53 +03:00
dm_task_destroy ( dmt ) ;
return ret ;
}
/* Fetch a string off src and duplicate it into *dest. */
2007-01-15 21:21:01 +03:00
/* FIXME: move to separate module to share with the daemon. */
static char * _fetch_string ( char * * src , const char delimiter )
2007-01-12 00:54:53 +03:00
{
char * p , * ret ;
if ( ( p = strchr ( * src , delimiter ) ) )
* p = 0 ;
if ( ( ret = dm_strdup ( * src ) ) )
* src + = strlen ( ret ) + 1 ;
if ( p )
* p = delimiter ;
2007-01-08 18:18:52 +03:00
return ret ;
2005-12-02 18:39:16 +03:00
}
2007-01-12 00:54:53 +03:00
/* Parse a device message from the daemon. */
2007-01-15 21:21:01 +03:00
static int _parse_message ( struct dm_event_daemon_message * msg , char * * dso_name ,
char * * devname , enum dm_event_mask * evmask )
2007-01-12 00:54:53 +03:00
{
char * p = msg - > data ;
2007-01-15 21:21:01 +03:00
if ( ( * dso_name = _fetch_string ( & p , ' ' ) ) & &
( * devname = _fetch_string ( & p , ' ' ) ) ) {
* evmask = atoi ( p ) ;
2007-01-12 00:54:53 +03:00
return 0 ;
}
return - ENOMEM ;
}
2007-01-08 18:18:52 +03:00
/*
* dm_event_get_registered_device
* @ dso_name
* @ device_path
2007-01-15 21:21:01 +03:00
* @ mask
2007-01-08 18:18:52 +03:00
* @ next
*
* FIXME : This function sucks .
*
* Returns : 1 if device found , 0 otherwise ( even on error )
*/
2005-12-02 18:39:16 +03:00
int dm_event_get_registered_device ( char * * dso_name , char * * device_path ,
2007-01-15 21:21:01 +03:00
enum dm_event_mask * mask , int next )
2005-12-02 18:39:16 +03:00
{
int ret ;
char * dso_name_arg = NULL , * device_path_arg = NULL ;
struct dm_event_daemon_message msg ;
2007-01-15 21:21:01 +03:00
if ( ! ( ret = _do_event ( next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
2007-01-12 00:54:53 +03:00
DM_EVENT_CMD_GET_REGISTERED_DEVICE ,
2007-01-15 21:21:01 +03:00
& msg , * dso_name , * device_path , * mask , 0 ) ) ) {
ret = ! _parse_message ( & msg , & dso_name_arg , & device_path_arg ,
mask ) ;
2007-01-12 00:54:53 +03:00
} else /* FIXME: Make sure this is ENOENT */
2007-01-08 18:18:52 +03:00
ret = 0 ;
if ( msg . data )
dm_free ( msg . data ) ;
2005-12-02 18:39:16 +03:00
2007-01-08 18:18:52 +03:00
if ( next ) {
2005-12-02 18:39:16 +03:00
if ( * dso_name )
2006-01-31 17:50:38 +03:00
dm_free ( * dso_name ) ;
2005-12-02 18:39:16 +03:00
if ( * device_path )
2006-01-31 17:50:38 +03:00
dm_free ( * device_path ) ;
2005-12-02 18:39:16 +03:00
* dso_name = dso_name_arg ;
* device_path = device_path_arg ;
} else {
if ( ! ( * dso_name ) )
* dso_name = dso_name_arg ;
if ( ! ( * device_path ) )
* device_path = device_path_arg ;
}
return ret ;
}
2007-01-12 23:22:11 +03:00
#if 0 /* left out for now */
2007-01-08 18:18:52 +03:00
int dm_event_set_timeout ( const char * device_path , uint32_t timeout )
2005-12-02 18:39:16 +03:00
{
struct dm_event_daemon_message msg ;
if ( ! device_exists ( device_path ) )
return - ENODEV ;
2007-01-15 21:21:01 +03:00
return _do_event ( DM_EVENT_CMD_SET_TIMEOUT , & msg ,
2005-12-02 18:39:16 +03:00
NULL , device_path , 0 , timeout ) ;
}
2007-01-08 18:18:52 +03:00
int dm_event_get_timeout ( const char * device_path , uint32_t * timeout )
2005-12-02 18:39:16 +03:00
{
int ret ;
struct dm_event_daemon_message msg ;
if ( ! device_exists ( device_path ) )
return - ENODEV ;
2007-01-15 21:21:01 +03:00
if ( ! ( ret = _do_event ( DM_EVENT_CMD_GET_TIMEOUT , & msg , NULL , device_path ,
2007-01-12 00:54:53 +03:00
0 , 0 ) ) )
2007-01-08 18:18:52 +03:00
* timeout = atoi ( msg . data ) ;
if ( msg . data )
dm_free ( msg . data ) ;
2005-12-02 18:39:16 +03:00
return ret ;
}
2007-01-12 00:54:53 +03:00
# endif