2007-01-08 18:18:52 +03:00
/*
2007-08-21 20:26:07 +04:00
* Copyright ( C ) 2005 - 2007 Red Hat , Inc . All rights reserved .
2005-12-02 18:39:16 +03:00
*
* 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
*/
2008-11-04 02:01:21 +03:00
# include "dmlib.h"
2005-12-02 18:39:16 +03:00
# 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 */
2007-02-02 20:08:51 +03:00
static int _sequence_nr = 0 ;
2007-01-12 00:54:53 +03:00
struct dm_event_handler {
2007-01-17 17:45:10 +03:00
char * dso ;
2007-01-15 21:21:01 +03:00
2007-01-17 17:45:10 +03:00
char * dev_name ;
2007-01-15 21:21:01 +03:00
2007-01-17 17:45:10 +03:00
char * uuid ;
2007-01-12 00:54:53 +03:00
int major ;
int minor ;
2007-01-22 18:03:57 +03:00
uint32_t timeout ;
2007-01-15 21:21:01 +03:00
enum dm_event_mask mask ;
2007-01-12 00:54:53 +03:00
} ;
2007-01-17 17:45:10 +03:00
static void _dm_event_handler_clear_dev_info ( struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-17 17:45:10 +03:00
if ( dmevh - > dev_name )
dm_free ( dmevh - > dev_name ) ;
if ( dmevh - > uuid )
dm_free ( dmevh - > uuid ) ;
2007-01-16 21:04:15 +03:00
dmevh - > dev_name = dmevh - > uuid = NULL ;
2007-01-15 21:21:01 +03:00
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-16 21:04:15 +03:00
dmevh - > dso = dmevh - > dev_name = dmevh - > uuid = NULL ;
2007-01-15 21:21:01 +03:00
dmevh - > major = dmevh - > minor = 0 ;
dmevh - > mask = 0 ;
2007-01-22 18:03:57 +03:00
dmevh - > timeout = 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-17 17:45:10 +03:00
_dm_event_handler_clear_dev_info ( dmevh ) ;
if ( dmevh - > dso )
dm_free ( dmevh - > dso ) ;
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-17 17:45:10 +03:00
int dm_event_handler_set_dso ( struct dm_event_handler * dmevh , const char * path )
2007-01-12 00:54:53 +03:00
{
2007-01-17 17:45:10 +03:00
if ( ! path ) /* noop */
return 0 ;
if ( dmevh - > dso )
dm_free ( dmevh - > dso ) ;
dmevh - > dso = dm_strdup ( path ) ;
if ( ! dmevh - > dso )
return - ENOMEM ;
return 0 ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-17 17:45:10 +03:00
int dm_event_handler_set_dev_name ( struct dm_event_handler * dmevh , const char * dev_name )
2007-01-12 00:54:53 +03:00
{
2007-01-17 17:45:10 +03:00
if ( ! dev_name )
return 0 ;
2007-01-15 21:21:01 +03:00
2007-01-17 17:45:10 +03:00
_dm_event_handler_clear_dev_info ( dmevh ) ;
dmevh - > dev_name = dm_strdup ( dev_name ) ;
if ( ! dmevh - > dev_name )
return - ENOMEM ;
return 0 ;
2007-01-12 00:54:53 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-17 17:45:10 +03:00
int dm_event_handler_set_uuid ( struct dm_event_handler * dmevh , const char * uuid )
2007-01-12 00:54:53 +03:00
{
2007-01-17 17:45:10 +03:00
if ( ! uuid )
return 0 ;
_dm_event_handler_clear_dev_info ( dmevh ) ;
2007-01-15 21:21:01 +03:00
2007-01-17 17:45:10 +03:00
dmevh - > uuid = dm_strdup ( uuid ) ;
if ( ! dmevh - > dev_name )
return - ENOMEM ;
return 0 ;
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-17 17:45:10 +03:00
_dm_event_handler_clear_dev_info ( dmevh ) ;
2007-01-15 21:21:01 +03:00
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-17 17:45:10 +03:00
_dm_event_handler_clear_dev_info ( 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-22 18:03:57 +03:00
void dm_event_handler_set_timeout ( struct dm_event_handler * dmevh , int timeout )
{
dmevh - > timeout = timeout ;
}
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-16 21:04:15 +03:00
const char * dm_event_handler_get_dev_name ( const struct dm_event_handler * dmevh )
2007-01-12 00:54:53 +03:00
{
2007-01-16 21:04:15 +03:00
return dmevh - > dev_name ;
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-22 18:03:57 +03:00
int dm_event_handler_get_timeout ( const struct dm_event_handler * dmevh )
{
return dmevh - > timeout ;
}
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
}
2007-02-02 20:08:51 +03:00
static int _check_message_id ( struct dm_event_daemon_message * msg )
{
int pid , seq_nr ;
if ( ( sscanf ( msg - > data , " %d:%d " , & pid , & seq_nr ) ! = 2 ) | |
( pid ! = getpid ( ) ) | | ( seq_nr ! = _sequence_nr ) ) {
log_error ( " Ignoring out-of-sequence reply from dmeventd. "
" Expected %d:%d but received %s " , getpid ( ) ,
_sequence_nr , msg - > data ) ;
return 0 ;
}
return 1 ;
}
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 ) ;
2007-02-02 20:08:51 +03:00
char drainbuf [ 128 ] ;
struct timeval tval = { 0 , 0 } ;
2007-01-08 18:18:52 +03:00
* ( ( 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
2007-02-02 20:08:51 +03:00
/* drain the answer fifo */
while ( 1 ) {
FD_ZERO ( & fds ) ;
FD_SET ( fifos - > server , & fds ) ;
tval . tv_usec = 100 ;
ret = select ( fifos - > server + 1 , & fds , NULL , NULL , & tval ) ;
if ( ( ret < 0 ) & & ( errno ! = EINTR ) ) {
log_error ( " Unable to talk to event daemon " ) ;
return 0 ;
}
if ( ret = = 0 )
break ;
read ( fifos - > server , drainbuf , 127 ) ;
}
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 ,
2007-01-16 21:04:15 +03:00
const char * dso_name , const char * dev_name ,
2007-01-15 21:21:01 +03:00
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-16 21:04:15 +03:00
const char * dev = dev_name ? dev_name : " " ;
2007-02-02 20:08:51 +03:00
const char * fmt = " %d:%d %s %s %u % " PRIu32 ;
2007-01-17 00:13:07 +03:00
int msg_size ;
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-02-02 20:08:51 +03:00
if ( cmd = = DM_EVENT_CMD_HELLO )
fmt = " %d:%d HELLO " ;
if ( ( msg_size = dm_asprintf ( & ( msg - > data ) , fmt , getpid ( ) , _sequence_nr ,
dso , dev , evmask , timeout ) ) < 0 ) {
2007-01-15 21:21:01 +03:00
log_error ( " _daemon_talk: message allocation failed " ) ;
2007-01-17 00:13:07 +03:00
return - ENOMEM ;
2007-01-15 21:21:01 +03:00
}
2007-01-17 00:13:07 +03:00
msg - > size = msg_size ;
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 ;
2007-04-19 23:10:19 +04:00
dm_free ( msg - > data ) ;
msg - > data = 0 ;
2005-12-02 18:39:16 +03:00
return - EIO ;
}
2007-02-02 20:08:51 +03:00
do {
2007-04-19 23:10:19 +04:00
if ( msg - > data )
dm_free ( msg - > data ) ;
msg - > data = 0 ;
2007-02-02 20:08:51 +03:00
if ( ! _daemon_read ( fifos , msg ) ) {
stack ;
return - EIO ;
}
} while ( ! _check_message_id ( msg ) ) ;
_sequence_nr + + ;
2005-12-02 18:39:16 +03:00
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 ) ;
2007-01-16 21:04:15 +03:00
else if ( dmevh - > dev_name )
dm_task_set_name ( dmt , dmevh - > dev_name ) ;
2007-01-15 21:21:01 +03:00
else if ( dmevh - > major & & dmevh - > minor ) {
dm_task_set_major ( dmt , dmevh - > major ) ;
dm_task_set_minor ( dmt , dmevh - > minor ) ;
2007-01-15 22:47:49 +03:00
}
2007-01-15 21:21:01 +03:00
/* 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 22:47:49 +03:00
if ( ! dm_task_get_info ( dmt , & info ) ) {
2007-01-15 21:21:01 +03:00
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 ,
2007-01-22 18:03:57 +03:00
const char * dso_name , const char * dev_name ,
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-02-02 20:08:51 +03:00
ret = _daemon_talk ( & fifos , msg , DM_EVENT_CMD_HELLO , 0 , 0 , 0 , 0 ) ;
2007-04-19 23:10:19 +04:00
if ( msg - > data )
dm_free ( msg - > data ) ;
msg - > data = 0 ;
2007-02-02 20:08:51 +03:00
if ( ! ret )
ret = _daemon_talk ( & fifos , msg , cmd , dso_name , dev_name , 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 ;
2007-02-02 20:08:51 +03:00
struct dm_event_daemon_message msg = { 0 , 0 , NULL } ;
2005-12-02 18:39:16 +03:00
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 ,
2007-01-22 18:03:57 +03:00
dmevh - > dso , uuid , dmevh - > mask , dmevh - > timeout ) ) < 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 ;
2007-02-02 20:08:51 +03:00
struct dm_event_daemon_message msg = { 0 , 0 , NULL } ;
2005-12-02 18:39:16 +03:00
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 ,
2007-01-22 18:03:57 +03:00
dmevh - > dso , uuid , dmevh - > mask , dmevh - > timeout ) ) < 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. */
2007-01-17 00:13:07 +03:00
static char * _fetch_string ( char * * src , const int 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 ,
2007-01-17 02:03:13 +03:00
char * * uuid , enum dm_event_mask * evmask )
2007-01-12 00:54:53 +03:00
{
2007-02-02 20:08:51 +03:00
char * id = NULL ;
2007-01-12 00:54:53 +03:00
char * p = msg - > data ;
2007-02-02 20:08:51 +03:00
if ( ( id = _fetch_string ( & p , ' ' ) ) & &
( * dso_name = _fetch_string ( & p , ' ' ) ) & &
2007-01-17 02:03:13 +03:00
( * uuid = _fetch_string ( & p , ' ' ) ) ) {
2007-01-15 21:21:01 +03:00
* evmask = atoi ( p ) ;
2007-01-12 00:54:53 +03:00
2007-02-02 20:08:51 +03:00
dm_free ( id ) ;
2007-01-12 00:54:53 +03:00
return 0 ;
}
2007-02-02 20:08:51 +03:00
if ( id )
dm_free ( id ) ;
2007-01-12 00:54:53 +03:00
return - ENOMEM ;
}
2007-01-08 18:18:52 +03:00
/*
2007-08-05 04:13:02 +04:00
* Returns 0 if handler found ; error ( - ENOMEM , - ENOENT ) otherwise .
2007-01-08 18:18:52 +03:00
*/
2007-01-17 02:03:13 +03:00
int dm_event_get_registered_device ( struct dm_event_handler * dmevh , int next )
2005-12-02 18:39:16 +03:00
{
2007-02-02 20:08:51 +03:00
int ret = 0 ;
2007-01-17 17:45:10 +03:00
const char * uuid = NULL ;
2007-01-17 02:03:13 +03:00
char * reply_dso = NULL , * reply_uuid = NULL ;
2007-02-02 20:08:51 +03:00
enum dm_event_mask reply_mask = 0 ;
struct dm_task * dmt = NULL ;
struct dm_event_daemon_message msg = { 0 , 0 , NULL } ;
2005-12-02 18:39:16 +03:00
2007-01-17 02:03:13 +03:00
if ( ! ( dmt = _get_device_info ( dmevh ) ) ) {
stack ;
return 0 ;
}
uuid = dm_task_get_uuid ( dmt ) ;
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-17 02:03:13 +03:00
& msg , dmevh - > dso , uuid , dmevh - > mask , 0 ) ) ) {
/* FIXME this will probably horribly break if we get
ill - formatted reply */
ret = _parse_message ( & msg , & reply_dso , & reply_uuid , & reply_mask ) ;
2007-01-17 17:45:10 +03:00
} else {
2007-01-17 02:03:13 +03:00
ret = - ENOENT ;
2007-01-17 17:45:10 +03:00
goto fail ;
}
2007-01-08 18:18:52 +03:00
2007-01-17 17:45:10 +03:00
dm_task_destroy ( dmt ) ;
2007-08-05 04:13:02 +04:00
dmt = NULL ;
2007-01-17 17:45:10 +03:00
if ( msg . data ) {
2007-01-08 18:18:52 +03:00
dm_free ( msg . data ) ;
2007-01-17 17:45:10 +03:00
msg . data = NULL ;
}
_dm_event_handler_clear_dev_info ( dmevh ) ;
dmevh - > uuid = dm_strdup ( reply_uuid ) ;
if ( ! dmevh - > uuid ) {
ret = - ENOMEM ;
goto fail ;
}
if ( ! ( dmt = _get_device_info ( dmevh ) ) ) {
ret = - ENXIO ; /* dmeventd probably gave us bogus uuid back */
goto fail ;
}
2005-12-02 18:39:16 +03:00
2007-01-17 02:03:13 +03:00
dm_event_handler_set_dso ( dmevh , reply_dso ) ;
dm_event_handler_set_event_mask ( dmevh , reply_mask ) ;
2007-04-19 23:10:19 +04:00
2007-11-27 15:26:06 +03:00
if ( reply_dso ) {
2007-04-19 23:10:19 +04:00
dm_free ( reply_dso ) ;
2007-11-27 15:26:06 +03:00
reply_dso = NULL ;
}
if ( reply_uuid ) {
2007-04-19 23:10:19 +04:00
dm_free ( reply_uuid ) ;
2007-11-27 15:26:06 +03:00
reply_uuid = NULL ;
}
2007-04-19 23:10:19 +04:00
2007-01-17 17:45:10 +03:00
dmevh - > dev_name = dm_strdup ( dm_task_get_name ( dmt ) ) ;
if ( ! dmevh - > dev_name ) {
ret = - ENOMEM ;
goto fail ;
}
struct dm_info info ;
if ( ! dm_task_get_info ( dmt , & info ) ) {
ret = - 1 ;
goto fail ;
}
dmevh - > major = info . major ;
dmevh - > minor = info . minor ;
2007-01-17 02:03:13 +03:00
dm_task_destroy ( dmt ) ;
2005-12-02 18:39:16 +03:00
return ret ;
2007-01-17 17:45:10 +03:00
fail :
if ( msg . data )
dm_free ( msg . data ) ;
2007-04-19 23:10:19 +04:00
if ( reply_dso )
dm_free ( reply_dso ) ;
if ( reply_uuid )
dm_free ( reply_uuid ) ;
2007-01-17 17:45:10 +03:00
_dm_event_handler_clear_dev_info ( dmevh ) ;
2007-08-03 02:31:59 +04:00
if ( dmt )
dm_task_destroy ( dmt ) ;
2007-01-17 17:45:10 +03:00
return ret ;
2005-12-02 18:39:16 +03:00
}
2007-01-12 23:22:11 +03:00
#if 0 /* left out for now */
2007-02-02 20:08:51 +03:00
static char * _skip_string ( char * src , const int delimiter )
{
src = srtchr ( src , delimiter ) ;
if ( src & & * ( src + 1 ) )
return src + 1 ;
return NULL ;
}
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
{
2007-02-02 20:08:51 +03:00
struct dm_event_daemon_message msg = { 0 , 0 , NULL } ;
2005-12-02 18:39:16 +03:00
if ( ! device_exists ( device_path ) )
return - ENODEV ;
2007-01-22 18:03:57 +03:00
2007-01-15 21:21:01 +03:00
return _do_event ( DM_EVENT_CMD_SET_TIMEOUT , & msg ,
2007-01-22 18:03:57 +03:00
NULL , device_path , 0 , timeout ) ;
2005-12-02 18:39:16 +03:00
}
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 ;
2007-02-02 20:08:51 +03:00
struct dm_event_daemon_message msg = { 0 , 0 , NULL } ;
2005-12-02 18:39:16 +03:00
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-02-02 20:08:51 +03:00
0 , 0 ) ) ) {
char * p = _skip_string ( msg . data , ' ' ) ;
if ( ! p ) {
log_error ( " malformed reply from dmeventd '%s' \n " ,
msg . data ) ;
return - EIO ;
}
* timeout = atoi ( p ) ;
}
2007-01-08 18:18:52 +03:00
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