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 <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
2010-08-17 02:54:35 +04:00
char * dmeventd_path ;
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
{
2010-08-16 22:19:46 +04:00
dm_free ( dmevh - > dev_name ) ;
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 )
{
2014-04-29 15:21:15 +04:00
struct dm_event_handler * dmevh ;
2005-12-02 18:39:16 +03:00
2012-06-20 12:35:24 +04:00
if ( ! ( dmevh = dm_zalloc ( sizeof ( * dmevh ) ) ) ) {
log_error ( " Failed to allocate event handler. " ) ;
2007-01-12 00:54:53 +03:00
return NULL ;
2012-06-20 12:35:24 +04:00
}
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 ) ;
2010-08-16 22:19:46 +04:00
dm_free ( dmevh - > dso ) ;
2010-08-17 02:54:35 +04:00
dm_free ( dmevh - > dmeventd_path ) ;
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
2010-08-17 02:54:35 +04:00
int dm_event_handler_set_dmeventd_path ( struct dm_event_handler * dmevh , const char * dmeventd_path )
{
if ( ! dmeventd_path ) /* noop */
return 0 ;
dm_free ( dmevh - > dmeventd_path ) ;
2014-04-29 15:21:15 +04:00
if ( ! ( dmevh - > dmeventd_path = dm_strdup ( dmeventd_path ) ) )
2010-08-17 02:54:35 +04:00
return - ENOMEM ;
return 0 ;
}
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 ;
2014-04-29 15:21:15 +04:00
2010-08-16 22:19:46 +04:00
dm_free ( dmevh - > dso ) ;
2007-01-17 17:45:10 +03:00
2014-04-29 15:21:15 +04:00
if ( ! ( dmevh - > dso = dm_strdup ( path ) ) )
2007-01-17 17:45:10 +03:00
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 ) ;
2014-04-29 15:21:15 +04:00
if ( ! ( dmevh - > dev_name = dm_strdup ( dev_name ) ) )
2007-01-17 17:45:10 +03:00
return - ENOMEM ;
2014-04-29 15:21:15 +04:00
2007-01-17 17:45:10 +03:00
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
2014-04-29 15:21:15 +04:00
if ( ! ( dmevh - > uuid = dm_strdup ( uuid ) ) )
2007-01-17 17:45:10 +03:00
return - ENOMEM ;
2014-04-29 15:21:15 +04:00
2007-01-17 17:45:10 +03:00
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
size_t size = 2 * sizeof ( uint32_t ) ; /* status + size */
2010-10-25 15:57:06 +04:00
uint32_t * header = alloca ( size ) ;
char * buf = ( char * ) header ;
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. */
2014-04-29 15:23:14 +04:00
struct timeval tval = { . tv_sec = 1 } ;
2005-12-02 18:39:16 +03:00
FD_ZERO ( & fds ) ;
FD_SET ( fifos - > server , & fds ) ;
2014-04-29 15:23:14 +04: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 ;
}
2012-03-12 18:46:53 +04:00
if ( ( ret = = 0 ) & & ( i > 4 ) & & ! bytes ) {
2012-02-28 15:03:24 +04:00
log_error ( " No input from event server. " ) ;
2012-02-15 17:56:47 +04: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 ;
2010-10-25 15:57:06 +04:00
if ( header & & ( bytes = = 2 * sizeof ( uint32_t ) ) ) {
msg - > cmd = ntohl ( header [ 0 ] ) ;
msg - > size = ntohl ( header [ 1 ] ) ;
2007-01-08 18:18:52 +03:00
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 ) {
2010-08-16 22:19:46 +04:00
dm_free ( msg - > data ) ;
2007-01-08 18:18:52 +03:00
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
{
2014-04-18 13:27:07 +04:00
int ret ;
2005-12-02 18:39:16 +03:00
fd_set fds ;
2014-04-18 13:27:07 +04:00
size_t bytes = 0 ;
2007-01-12 00:54:53 +03:00
size_t size = 2 * sizeof ( uint32_t ) + msg - > size ;
2010-10-25 15:57:06 +04:00
uint32_t * header = alloca ( size ) ;
char * buf = ( char * ) header ;
2007-02-02 20:08:51 +03:00
char drainbuf [ 128 ] ;
2007-01-08 18:18:52 +03:00
2010-10-25 15:57:06 +04:00
header [ 0 ] = htonl ( msg - > cmd ) ;
header [ 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 ) {
2014-04-18 13:31:59 +04:00
struct timeval tval = { . tv_usec = 100 } ;
2007-02-02 20:08:51 +03:00
FD_ZERO ( & fds ) ;
FD_SET ( fifos - > server , & fds ) ;
ret = select ( fifos - > server + 1 , & fds , NULL , NULL , & tval ) ;
2014-08-19 16:20:22 +04:00
if ( ret < 0 ) {
if ( errno = = EINTR )
continue ;
2007-02-02 20:08:51 +03:00
log_error ( " Unable to talk to event daemon " ) ;
return 0 ;
}
if ( ret = = 0 )
break ;
2014-04-18 13:27:07 +04:00
ret = read ( fifos - > server , drainbuf , sizeof ( drainbuf ) ) ;
2014-08-19 16:20:22 +04:00
if ( ret < 0 ) {
if ( ( errno = = EINTR ) | | ( errno = = EAGAIN ) )
continue ;
log_error ( " Unable to talk to event daemon " ) ;
return 0 ;
}
2007-02-02 20:08:51 +03:00
}
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
2010-10-25 15:57:06 +04:00
ret = write ( fifos - > client , 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
}
2010-10-20 19:12:12 +04:00
int daemon_talk ( struct dm_event_fifos * fifos ,
struct dm_event_daemon_message * msg , int cmd ,
const char * dso_name , const char * dev_name ,
enum dm_event_mask evmask , uint32_t timeout )
2005-12-02 18:39:16 +03:00
{
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 .
*/
2013-11-22 15:54:59 +04:00
if ( ( msg_size =
( ( cmd = = DM_EVENT_CMD_HELLO ) ?
dm_asprintf ( & ( msg - > data ) , " %d:%d HELLO " , getpid ( ) , _sequence_nr ) :
dm_asprintf ( & ( msg - > data ) , " %d:%d %s %s %u % " PRIu32 ,
getpid ( ) , _sequence_nr ,
dso_name ? : " - " , dev_name ? : " - " , 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
}
2013-11-22 15:54:59 +04:00
msg - > cmd = cmd ;
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 ) ;
2014-03-24 12:18:53 +04:00
msg - > data = NULL ;
2005-12-02 18:39:16 +03:00
return - EIO ;
}
2007-02-02 20:08:51 +03:00
do {
2010-08-16 22:19:46 +04:00
dm_free ( msg - > data ) ;
2014-03-24 12:18:53 +04:00
msg - > data = NULL ;
2007-04-19 23:10:19 +04:00
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
*/
2010-08-17 02:54:35 +04:00
static int _start_daemon ( char * dmeventd_path , 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 ;
2010-08-17 02:54:35 +04:00
char default_dmeventd_path [ ] = DMEVENTD_PATH ;
char * args [ ] = { dmeventd_path ? : default_dmeventd_path , NULL } ;
2007-01-08 18:18:52 +03:00
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 */
2012-02-28 14:14:06 +04:00
if ( close ( fifos - > client ) )
2013-11-25 16:46:34 +04:00
log_sys_debug ( " close " , fifos - > client_path ) ;
2007-01-08 18:18:52 +03:00
return 1 ;
} else if ( errno ! = ENXIO ) {
/* problem */
2012-02-28 14:14:06 +04:00
log_sys_error ( " open " , fifos - > client_path ) ;
2007-01-08 18:18:52 +03:00
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 */
2009-06-15 16:29:41 +04:00
2012-03-20 21:38:47 +04:00
if ( ( args [ 0 ] [ 0 ] = = ' / ' ) & & stat ( args [ 0 ] , & statbuf ) ) {
log_sys_error ( " stat " , args [ 0 ] ) ;
2011-01-06 12:45:05 +03:00
return 0 ;
2009-06-15 16:29:41 +04:00
}
2005-12-02 18:39:16 +03:00
pid = fork ( ) ;
if ( pid < 0 )
2012-02-28 14:14:06 +04:00
log_sys_error ( " fork " , " " ) ;
2005-12-02 18:39:16 +03:00
2007-01-08 18:18:52 +03:00
else if ( ! pid ) {
2010-01-14 13:11:26 +03:00
execvp ( args [ 0 ] , args ) ;
2010-10-20 19:12:12 +04:00
log_error ( " Unable to exec dmeventd: %s " , strerror ( errno ) ) ;
2009-07-14 01:26:41 +04: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
}
2010-10-20 19:12:12 +04:00
int init_fifos ( 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
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 ) {
2012-02-28 14:14:06 +04:00
log_sys_error ( " open " , fifos - > server_path ) ;
2005-12-02 18:39:16 +03:00
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 ) {
2012-02-28 14:14:06 +04:00
log_sys_error ( " flock " , fifos - > server_path ) ;
2013-11-28 15:21:06 +04:00
goto bad ;
2005-12-02 18:39:16 +03:00
}
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 ) {
2012-02-28 14:14:06 +04:00
log_sys_error ( " open " , fifos - > client_path ) ;
2013-11-28 15:21:06 +04:00
goto bad ;
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 ;
2013-11-28 15:21:06 +04:00
bad :
if ( close ( fifos - > server ) )
log_sys_debug ( " close " , fifos - > server_path ) ;
fifos - > server = - 1 ;
return 0 ;
2005-12-02 18:39:16 +03:00
}
2010-10-20 19:12:12 +04:00
/* Initialize client. */
static int _init_client ( char * dmeventd_path , struct dm_event_fifos * fifos )
{
if ( ! _start_daemon ( dmeventd_path , fifos ) )
return_0 ;
return init_fifos ( fifos ) ;
}
void fini_fifos ( struct dm_event_fifos * fifos )
2005-12-02 18:39:16 +03:00
{
2013-11-28 15:21:06 +04:00
if ( fifos - > client > = 0 & & close ( fifos - > client ) )
2013-11-25 16:46:34 +04:00
log_sys_debug ( " close " , fifos - > client_path ) ;
2013-11-28 15:21:06 +04:00
if ( fifos - > server > = 0 ) {
if ( flock ( fifos - > server , LOCK_UN ) )
2013-11-25 16:46:34 +04:00
log_sys_debug ( " flock unlock " , fifos - > server_path ) ;
2013-11-28 15:21:06 +04:00
if ( close ( fifos - > server ) )
2013-11-25 16:46:34 +04:00
log_sys_debug ( " close " , fifos - > server_path ) ;
2013-11-28 15:21:06 +04:00
}
2005-12-02 18:39:16 +03:00
}
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
2010-12-22 18:28:44 +03:00
if ( dmevh - > uuid ) {
if ( ! dm_task_set_uuid ( dmt , dmevh - > uuid ) )
goto_bad ;
} else if ( dmevh - > dev_name ) {
if ( ! dm_task_set_name ( dmt , dmevh - > dev_name ) )
goto_bad ;
} else if ( dmevh - > major & & dmevh - > minor ) {
if ( ! dm_task_set_major ( dmt , dmevh - > major ) | |
! dm_task_set_minor ( dmt , dmevh - > minor ) )
goto_bad ;
}
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 " ) ;
2010-12-22 18:28:44 +03:00
goto bad ;
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 " ) ;
2010-12-22 18:28:44 +03:00
goto bad ;
2007-01-15 21:21:01 +03:00
}
2005-12-02 18:39:16 +03:00
2007-01-15 21:21:01 +03:00
if ( ! info . exists ) {
2011-07-08 16:35:48 +04:00
log_error ( " _get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found " ,
2014-03-24 12:19:37 +04:00
dmevh - > uuid ? : " " ,
( ! dmevh - > uuid & & dmevh - > dev_name ) ? dmevh - > dev_name : " " ,
2011-07-08 16:35:48 +04:00
( ! dmevh - > uuid & & ! dmevh - > dev_name & & dmevh - > major > 0 ) ? " ( " : " " ,
( ! dmevh - > uuid & & ! dmevh - > dev_name & & dmevh - > major > 0 ) ? dmevh - > major : 0 ,
( ! dmevh - > uuid & & ! dmevh - > dev_name & & dmevh - > major > 0 ) ? " : " : " " ,
( ! dmevh - > uuid & & ! dmevh - > dev_name & & dmevh - > minor > 0 ) ? dmevh - > minor : 0 ,
( ! dmevh - > uuid & & ! dmevh - > dev_name & & dmevh - > major > 0 ) & & dmevh - > minor = = 0 ? " 0 " : " " ,
( ! dmevh - > uuid & & ! dmevh - > dev_name & & dmevh - > major > 0 ) ? " ) " : " " ) ;
2010-12-22 18:28:44 +03:00
goto bad ;
2007-01-15 21:21:01 +03:00
}
return dmt ;
2010-12-22 18:28:44 +03:00
bad :
2007-01-15 21:21:01 +03:00
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. */
2010-08-17 02:54:35 +04:00
static int _do_event ( int cmd , char * dmeventd_path , 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 ;
2013-11-28 15:21:06 +04:00
struct dm_event_fifos fifos = {
. server = - 1 ,
. client = - 1 ,
/* FIXME Make these either configurable or depend directly on dmeventd_path */
. client_path = DM_EVENT_FIFO_CLIENT ,
. server_path = DM_EVENT_FIFO_SERVER
} ;
2005-12-02 18:39:16 +03:00
2010-08-17 02:54:35 +04:00
if ( ! _init_client ( dmeventd_path , & fifos ) ) {
2005-12-02 18:39:16 +03:00
stack ;
return - ESRCH ;
}
2010-10-20 19:12:12 +04:00
ret = daemon_talk ( & fifos , msg , DM_EVENT_CMD_HELLO , NULL , NULL , 0 , 0 ) ;
2007-04-19 23:10:19 +04:00
2010-08-16 22:19:46 +04:00
dm_free ( msg - > data ) ;
2007-04-19 23:10:19 +04:00
msg - > data = 0 ;
2007-02-02 20:08:51 +03:00
if ( ! ret )
2010-10-20 19:12:12 +04:00
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? */
2010-10-20 19:12:12 +04:00
fini_fifos ( & 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 ;
2014-04-18 13:27:07 +04:00
struct dm_event_daemon_message msg = { 0 } ;
2005-12-02 18:39:16 +03:00
2013-07-01 13:27:11 +04:00
if ( ! ( dmt = _get_device_info ( dmevh ) ) )
return_0 ;
2005-12-02 18:39:16 +03:00
2007-01-12 00:54:53 +03:00
uuid = dm_task_get_uuid ( dmt ) ;
2014-02-10 17:51:14 +04:00
if ( ! strstr ( dmevh - > dso , " libdevmapper-event-lvm2thin.so " ) & &
! strstr ( dmevh - > dso , " libdevmapper-event-lvm2snapshot.so " ) & &
! strstr ( dmevh - > dso , " libdevmapper-event-lvm2mirror.so " ) & &
! strstr ( dmevh - > dso , " libdevmapper-event-lvm2raid.so " ) )
log_warn ( " WARNING: %s: dmeventd plugins are deprecated " , dmevh - > dso ) ;
2010-08-17 02:54:35 +04:00
if ( ( err = _do_event ( DM_EVENT_CMD_REGISTER_FOR_EVENT , dmevh - > dmeventd_path , & 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
2010-08-16 22:19:46 +04:00
dm_free ( msg . data ) ;
2007-01-08 18:18:52 +03:00
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 ;
2014-04-18 13:27:07 +04:00
struct dm_event_daemon_message msg = { 0 } ;
2005-12-02 18:39:16 +03:00
2013-07-01 13:27:11 +04:00
if ( ! ( dmt = _get_device_info ( dmevh ) ) )
return_0 ;
2005-12-02 18:39:16 +03:00
2007-01-12 00:54:53 +03:00
uuid = dm_task_get_uuid ( dmt ) ;
2010-08-17 02:54:35 +04:00
if ( ( err = _do_event ( DM_EVENT_CMD_UNREGISTER_FOR_EVENT , dmevh - > dmeventd_path , & 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
2010-08-16 22:19:46 +04:00
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
{
2014-03-24 12:19:56 +04:00
char * id ;
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-02-02 20:08:51 +03:00
dm_free ( id ) ;
2007-01-12 00:54:53 +03:00
return 0 ;
}
2014-03-24 12:20:18 +04:00
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 ;
2013-04-25 12:17:22 +04:00
struct dm_event_daemon_message msg = { 0 } ;
2010-03-24 14:36:48 +03:00
struct dm_info info ;
2005-12-02 18:39:16 +03:00
2007-01-17 02:03:13 +03:00
if ( ! ( dmt = _get_device_info ( dmevh ) ) ) {
2013-04-25 12:17:22 +04:00
log_debug ( " Device does not exists (uuid=%s, name=%s, %d:%d). " ,
dmevh - > uuid , dmevh - > dev_name ,
dmevh - > major , dmevh - > minor ) ;
ret = - ENODEV ;
goto fail ;
2007-01-17 02:03:13 +03:00
}
uuid = dm_task_get_uuid ( dmt ) ;
2011-01-06 13:45:41 +03:00
if ( _do_event ( next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE , dmevh - > dmeventd_path ,
& msg , dmevh - > dso , uuid , dmevh - > mask , 0 ) ) {
2012-03-01 14:41:48 +04:00
log_debug ( " %s: device not registered. " , dm_task_get_name ( dmt ) ) ;
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
2011-01-06 13:45:41 +03:00
/* 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
dm_task_destroy ( dmt ) ;
2007-08-05 04:13:02 +04:00
dmt = NULL ;
2007-01-17 17:45:10 +03:00
2010-08-16 22:19:46 +04:00
dm_free ( msg . data ) ;
msg . data = NULL ;
2007-01-17 17:45:10 +03:00
_dm_event_handler_clear_dev_info ( dmevh ) ;
2012-02-13 15:24:09 +04:00
if ( ! reply_uuid ) {
ret = - ENXIO ; /* dmeventd probably gave us bogus uuid back */
goto fail ;
}
2014-04-29 15:21:15 +04:00
if ( ! ( dmevh - > uuid = dm_strdup ( reply_uuid ) ) ) {
2007-01-17 17:45:10 +03:00
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
2010-08-16 22:19:46 +04:00
dm_free ( reply_dso ) ;
reply_dso = NULL ;
2007-11-27 15:26:06 +03:00
2010-08-16 22:19:46 +04:00
dm_free ( reply_uuid ) ;
reply_uuid = NULL ;
2007-04-19 23:10:19 +04:00
2014-04-29 15:21:15 +04:00
if ( ! ( dmevh - > dev_name = dm_strdup ( dm_task_get_name ( dmt ) ) ) ) {
2007-01-17 17:45:10 +03:00
ret = - ENOMEM ;
goto fail ;
}
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 :
2010-08-16 22:19:46 +04:00
dm_free ( msg . data ) ;
dm_free ( reply_dso ) ;
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
}
2011-04-04 20:11:09 +04:00
/*
* You can ( and have to ) call this at the stage of the protocol where
* daemon_talk ( fifos , & msg , DM_EVENT_CMD_HELLO , NULL , NULL , 0 , 0 )
*
* would be normally sent . This call will parse the version reply from
* dmeventd , in addition to above call . It is not safe to call this at any
* other place in the protocol .
*
* This is an internal function , not exposed in the public API .
*/
int dm_event_get_version ( struct dm_event_fifos * fifos , int * version ) {
char * p ;
2014-04-18 13:27:07 +04:00
struct dm_event_daemon_message msg = { 0 } ;
2011-04-04 20:11:09 +04:00
if ( daemon_talk ( fifos , & msg , DM_EVENT_CMD_HELLO , NULL , NULL , 0 , 0 ) )
return 0 ;
p = msg . data ;
* version = 0 ;
2013-04-19 19:03:50 +04:00
if ( ! p | | ! ( p = strchr ( p , ' ' ) ) ) /* Message ID */
return 0 ;
if ( ! ( p = strchr ( p + 1 , ' ' ) ) ) /* HELLO */
return 0 ;
if ( ( p = strchr ( p + 1 , ' ' ) ) ) /* HELLO, once more */
2011-04-04 20:11:09 +04:00
* version = atoi ( p ) ;
2013-04-19 19:03:50 +04:00
2011-04-04 20:11:09 +04:00
return 1 ;
}
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
{
2014-03-24 12:19:56 +04:00
struct dm_event_daemon_message msg = { 0 } ;
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 ;
2014-03-24 12:19:56 +04:00
struct dm_event_daemon_message msg = { 0 } ;
2005-12-02 18:39:16 +03:00
if ( ! device_exists ( device_path ) )
return - ENODEV ;
2014-04-29 15:21:15 +04:00
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 ) ;
2014-03-24 12:20:18 +04:00
dm_free ( msg . data ) ;
2007-02-02 20:08:51 +03:00
return - EIO ;
}
* timeout = atoi ( p ) ;
}
2014-03-24 12:20:18 +04:00
dm_free ( msg . data ) ;
2005-12-02 18:39:16 +03:00
return ret ;
}
2007-01-12 00:54:53 +03:00
# endif