2007-01-08 18:18:52 +03:00
/*
2015-10-10 17:40:52 +03:00
* Copyright ( C ) 2005 - 2015 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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-12-02 18:39:16 +03:00
*/
2018-12-14 18:28:26 +03:00
# include "libdevmapper-event.h"
2005-12-02 18:39:16 +03:00
# include "dmeventd.h"
2018-12-14 18:28:26 +03:00
# include "libdm/misc/dm-logging.h"
# include "base/memory/zalloc.h"
2018-05-14 14:16:43 +03:00
# include "lib/misc/intl.h"
2005-12-02 18:39:16 +03:00
# include <fcntl.h>
# include <sys/file.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
2007-01-12 00:54:53 +03:00
# include <arpa/inet.h> /* for htonl, ntohl */
2015-10-10 17:40:52 +03:00
# include <pthread.h>
# include <syslog.h>
2018-05-14 14:16:43 +03:00
# include <unistd.h>
2007-01-12 00:54:53 +03:00
2015-10-10 17:40:52 +03:00
static int _debug_level = 0 ;
static int _use_syslog = 0 ;
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
{
2018-06-08 15:40:53 +03:00
free ( dmevh - > dev_name ) ;
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
2018-06-08 15:40:53 +03:00
if ( ! ( dmevh = zalloc ( sizeof ( * dmevh ) ) ) ) {
2012-06-20 12:35:24 +04:00
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 ) ;
2018-06-08 15:40:53 +03:00
free ( dmevh - > dso ) ;
free ( dmevh - > dmeventd_path ) ;
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 ;
2018-06-08 15:40:53 +03:00
free ( dmevh - > dmeventd_path ) ;
2010-08-17 02:54:35 +04:00
2018-06-08 15:40:53 +03:00
if ( ! ( dmevh - > dmeventd_path = 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
2018-06-08 15:40:53 +03:00
free ( dmevh - > dso ) ;
2007-01-17 17:45:10 +03:00
2018-06-08 15:40:53 +03:00
if ( ! ( dmevh - > dso = 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 ) ;
2018-06-08 15:40:53 +03:00
if ( ! ( dmevh - > dev_name = 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
2018-06-08 15:40:53 +03:00
if ( ! ( dmevh - > uuid = 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. "
2015-10-09 22:57:48 +03:00
" Expected %d:%d but received %s. " , getpid ( ) ,
2007-02-02 20:08:51 +03:00
_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 ) {
2015-10-09 22:57:48 +03:00
log_error ( " Unable to read from event server. " ) ;
2020-01-29 18:41:28 +03:00
goto bad ;
2005-12-20 01:56:47 +03:00
}
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. " ) ;
2020-01-29 18:41:28 +03:00
goto bad ;
2012-02-15 17:56:47 +04:00
}
2007-01-08 18:18:52 +03:00
}
if ( ret < 1 ) {
log_error ( " Unable to read from event server. " ) ;
2020-01-29 18:41:28 +03:00
goto bad ;
2007-01-08 18:18:52 +03:00
}
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 ;
2017-07-19 17:16:12 +03:00
log_error ( " Unable to read from event server. " ) ;
2020-01-29 18:41:28 +03:00
goto bad ;
2005-12-20 01:56:47 +03:00
}
bytes + = ret ;
2020-01-29 18:41:28 +03:00
if ( ! msg - > data & & ( bytes = = 2 * sizeof ( uint32_t ) ) ) {
2010-10-25 15:57:06 +04:00
msg - > cmd = ntohl ( header [ 0 ] ) ;
2007-01-08 18:18:52 +03:00
bytes = 0 ;
2020-01-29 18:41:28 +03:00
if ( ! ( size = msg - > size = ntohl ( header [ 1 ] ) ) )
break ;
if ( ! ( buf = msg - > data = malloc ( msg - > size ) ) ) {
log_error ( " Unable to allocate message data. " ) ;
return 0 ;
}
2007-01-08 18:18:52 +03:00
}
2005-12-02 18:39:16 +03:00
}
2020-01-29 18:41:28 +03:00
if ( bytes = = size )
return 1 ;
bad :
free ( msg - > data ) ;
msg - > data = NULL ;
return 0 ;
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 ;
2015-10-09 22:57:48 +03:00
log_error ( " Unable to talk to event daemon. " ) ;
2007-02-02 20:08:51 +03:00
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 ;
2015-10-09 22:57:48 +03:00
log_error ( " Unable to talk to event daemon. " ) ;
2014-08-19 16:20:22 +04:00
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 ) ) {
2015-10-09 22:57:48 +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 ;
2017-07-19 17:16:12 +03:00
log_error ( " Unable to talk to event daemon. " ) ;
return 0 ;
2005-12-20 01:56:47 +03:00
}
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 ) {
2015-10-09 22:57:48 +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 ;
2018-06-08 15:40:53 +03:00
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 {
2018-06-08 15:40:53 +03:00
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
}
2024-04-19 21:45:00 +03:00
2005-12-02 18:39:16 +03:00
/*
2024-04-19 21:45:00 +03:00
* Check for usable client fifo file
2005-12-02 18:39:16 +03:00
*
2024-04-19 21:45:00 +03:00
* Returns : 2 cliant path does not exists , dmeventd should be restarted
* 1 on success , 0 otherwise
2005-12-02 18:39:16 +03:00
*/
2024-04-19 21:45:00 +03:00
static int _check_for_usable_fifos ( char * dmeventd_path , struct dm_event_fifos * fifos )
2005-12-02 18:39:16 +03:00
{
2007-01-08 18:18:52 +03:00
struct stat statbuf ;
2015-12-08 03:54:32 +03:00
/*
* FIXME Explicitly verify the code ' s requirement that client_path is secure :
* - All parent directories owned by root without group / other write access unless sticky .
*/
/* If client fifo path exists, only use it if it is root-owned fifo mode 0600 */
if ( ( lstat ( fifos - > client_path , & statbuf ) < 0 ) ) {
if ( errno = = ENOENT )
/* Jump ahead if fifo does not already exist. */
2024-04-19 21:45:00 +03:00
return 2 ;
2015-12-08 03:54:32 +03:00
else {
log_sys_error ( " stat " , fifos - > client_path ) ;
return 0 ;
}
} else if ( ! S_ISFIFO ( statbuf . st_mode ) ) {
log_error ( " %s must be a fifo. " , fifos - > client_path ) ;
return 0 ;
} else if ( statbuf . st_uid ) {
log_error ( " %s must be owned by uid 0. " , fifos - > client_path ) ;
return 0 ;
} else if ( statbuf . st_mode & ( S_IEXEC | S_IRWXG | S_IRWXO ) ) {
log_error ( " %s must have mode 0600. " , fifos - > client_path ) ;
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 ) {
2015-12-08 03:54:32 +03:00
/* Should never happen if all the above checks passed. */
2015-11-07 23:50:27 +03:00
if ( ( fstat ( fifos - > client , & statbuf ) < 0 ) | |
2015-12-08 03:54:32 +03:00
! S_ISFIFO ( statbuf . st_mode ) | | statbuf . st_uid | |
( statbuf . st_mode & ( S_IEXEC | S_IRWXG | S_IRWXO ) ) ) {
log_error ( " %s is no longer a secure root-owned fifo with mode 0600. " , fifos - > client_path ) ;
if ( close ( fifos - > client ) )
log_sys_debug ( " close " , fifos - > client_path ) ;
2015-11-07 23:50:27 +03:00
return 0 ;
}
2007-01-08 18:18:52 +03:00
/* 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 ) ;
2024-04-19 21:45:00 +03:00
fifos - > client = - 1 ;
2007-01-08 18:18:52 +03:00
return 1 ;
2017-07-19 17:16:12 +03:00
}
if ( errno ! = ENXIO & & errno ! = ENOENT ) {
2007-01-08 18:18:52 +03:00
/* 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
2024-04-19 21:45:00 +03:00
return 2 ;
}
2009-06-15 16:29:41 +04:00
2024-04-19 21:45:00 +03:00
/*
* start_daemon
*
* This function forks off a process ( dmeventd ) that will handle
* 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 ) .
*
* Returns : 1 on success , 0 otherwise
*/
static int _start_daemon ( char * dmeventd_path , struct dm_event_fifos * fifos )
{
struct stat statbuf ;
char default_dmeventd_path [ ] = DMEVENTD_PATH ;
char * args [ ] = { dmeventd_path ? : default_dmeventd_path , NULL } ;
int pid , ret = 0 ;
int status ;
switch ( _check_for_usable_fifos ( dmeventd_path , fifos ) ) {
case 0 : return_0 ;
case 1 : return 1 ; /* Already running dmeventd */
}
/* server is not running */
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 ) ;
2015-10-09 22:57:48 +03: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 )
2015-10-09 22:57:48 +03:00
log_error ( " Unable to start dmeventd: %s. " ,
2007-01-12 00:54:53 +03:00
strerror ( errno ) ) ;
2007-01-08 18:18:52 +03:00
else if ( WEXITSTATUS ( status ) )
log_error ( " Unable to start dmeventd. " ) ;
2024-04-19 21:45:00 +03:00
else {
/* Loop here till forked dmeventd is serving fifos */
for ( ret = 100 ; ret > 0 ; - - ret )
switch ( _check_for_usable_fifos ( dmeventd_path , fifos ) ) {
case 0 : return_0 ;
case 1 : return 1 ;
case 2 : usleep ( 1000 ) ; continue ;
}
/* ret == 0 */
log_error ( " Dmeventd is not serving fifos. " ) ;
}
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 ) ;
2024-04-12 00:19:20 +03:00
goto bad_no_unlock ;
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 :
2024-04-12 00:19:20 +03:00
if ( flock ( fifos - > server , LOCK_UN ) )
log_sys_debug ( " flock unlock " , fifos - > server_path ) ;
bad_no_unlock :
2013-11-28 15:21:06 +04:00
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
}
2023-09-25 14:01:24 +03:00
fifos - > client = fifos - > server = - 1 ;
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 ) ) ) {
2015-10-09 22:57:48 +03:00
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 ) ) {
2015-10-09 22:57:48 +03:00
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 ) ) {
2015-10-09 22:57:48 +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 ) {
2015-10-09 22:57:48 +03: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 = {
. client = - 1 ,
2020-08-29 22:37:39 +03:00
. server = - 1 ,
2013-11-28 15:21:06 +04:00
/* 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 ) ) {
2015-11-08 19:10:38 +03:00
ret = - ESRCH ;
goto_out ;
2005-12-02 18:39:16 +03:00
}
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
2018-06-08 15:40:53 +03:00
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 ) ;
2015-11-08 19:10:38 +03:00
out :
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 " ) & &
2018-07-09 12:41:26 +03:00
! strstr ( dmevh - > dso , " libdevmapper-event-lvm2vdo.so " ) & &
2014-02-10 17:51:14 +04:00
! strstr ( dmevh - > dso , " libdevmapper-event-lvm2snapshot.so " ) & &
! strstr ( dmevh - > dso , " libdevmapper-event-lvm2mirror.so " ) & &
! strstr ( dmevh - > dso , " libdevmapper-event-lvm2raid.so " ) )
2015-10-09 22:57:48 +03:00
log_warn ( " WARNING: %s: dmeventd plugins are deprecated. " , dmevh - > dso ) ;
2014-02-10 17:51:14 +04:00
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 ) {
2015-10-09 22:57:48 +03:00
log_error ( " %s: event registration failed: %s. " ,
2007-01-12 00:54:53 +03:00
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
2018-06-08 15:40:53 +03:00
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 ) {
2015-10-09 22:57:48 +03:00
log_error ( " %s: event deregistration failed: %s. " ,
2007-01-12 00:54:53 +03:00
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
2018-06-08 15:40:53 +03:00
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 ;
2021-09-20 14:51:20 +03:00
size_t len = ( p = strchr ( * src , delimiter ) ) ?
2021-09-22 17:45:33 +03:00
( size_t ) ( p - * src ) : strlen ( * src ) ;
2007-01-12 00:54:53 +03:00
2021-09-20 14:51:20 +03:00
if ( ( ret = strndup ( * src , len ) ) )
* src + = len + 1 ;
2007-01-12 00:54:53 +03:00
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 ) ;
2018-06-08 15:40:53 +03:00
free ( id ) ;
2007-01-12 00:54:53 +03:00
return 0 ;
}
2018-06-08 15:40:53 +03:00
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 ) ;
2015-12-08 03:54:32 +03:00
/* FIXME Distinguish errors connecting to daemon */
2018-01-29 18:28:57 +03:00
if ( ( ret = _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 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
2018-06-08 15:40:53 +03:00
free ( msg . data ) ;
2010-08-16 22:19:46 +04:00
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
2018-06-08 15:40:53 +03:00
if ( ! ( dmevh - > uuid = 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
2018-06-08 15:40:53 +03:00
free ( reply_dso ) ;
2010-08-16 22:19:46 +04:00
reply_dso = NULL ;
2007-11-27 15:26:06 +03:00
2018-06-08 15:40:53 +03:00
free ( reply_uuid ) ;
2010-08-16 22:19:46 +04:00
reply_uuid = NULL ;
2007-04-19 23:10:19 +04:00
2018-06-08 15:40:53 +03:00
if ( ! ( dmevh - > dev_name = 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 :
2018-06-08 15:40:53 +03:00
free ( msg . data ) ;
free ( reply_dso ) ;
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 } ;
2023-09-25 12:47:40 +03:00
int ret = 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 */
2023-09-25 12:47:40 +03:00
goto out ;
2013-04-19 19:03:50 +04:00
if ( ! ( p = strchr ( p + 1 , ' ' ) ) ) /* HELLO */
2023-09-25 12:47:40 +03:00
goto out ;
2013-04-19 19:03:50 +04:00
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
2023-09-25 12:47:40 +03:00
ret = 1 ;
out :
free ( msg . data ) ;
return ret ;
2011-04-04 20:11:09 +04:00
}
2016-04-08 12:36:02 +03:00
void dm_event_log_set ( int debug_log_level , int use_syslog )
2015-10-10 17:40:52 +03:00
{
2016-04-08 12:36:02 +03:00
_debug_level = debug_log_level ;
2015-10-10 17:40:52 +03:00
_use_syslog = use_syslog ;
}
void dm_event_log ( const char * subsys , int level , const char * file ,
int line , int dm_errno_or_class ,
const char * format , va_list ap )
{
2016-11-02 16:40:12 +03:00
static int _abort_on_internal_errors = - 1 ;
2015-10-10 17:40:52 +03:00
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER ;
2023-09-24 23:56:46 +03:00
static long long _start = 0 ;
2015-10-10 17:40:52 +03:00
const char * indent = " " ;
2016-11-02 16:39:13 +03:00
FILE * stream = log_stderr ( level ) ? stderr : stdout ;
2015-11-07 22:41:15 +03:00
int prio ;
2023-09-24 23:56:46 +03:00
long long now , now_nsec ;
2016-11-03 14:01:01 +03:00
int log_with_debug = 0 ;
if ( subsys [ 0 ] = = ' # ' ) {
/* Subsystems starting with '#' are logged
* only when debugging is enabled . */
log_with_debug + + ;
subsys + + ;
}
2015-10-10 17:40:52 +03:00
2016-11-02 16:39:13 +03:00
switch ( log_level ( level ) ) {
2015-10-10 17:40:52 +03:00
case _LOG_DEBUG :
2016-11-03 14:01:01 +03:00
/* Never shown without -ddd */
2015-10-10 17:40:52 +03:00
if ( _debug_level < 3 )
return ;
prio = LOG_DEBUG ;
indent = " " ;
break ;
case _LOG_INFO :
2016-11-03 14:01:01 +03:00
if ( log_with_debug & & _debug_level < 2 )
2015-10-10 17:40:52 +03:00
return ;
prio = LOG_INFO ;
indent = " " ;
break ;
case _LOG_NOTICE :
2016-11-03 14:01:01 +03:00
if ( log_with_debug & & _debug_level < 1 )
2015-10-10 17:40:52 +03:00
return ;
prio = LOG_NOTICE ;
indent = " " ;
break ;
case _LOG_WARN :
prio = LOG_WARNING ;
break ;
case _LOG_ERR :
prio = LOG_ERR ;
stream = stderr ;
break ;
default :
prio = LOG_CRIT ;
}
/* Serialize to keep lines readable */
pthread_mutex_lock ( & _log_mutex ) ;
if ( _use_syslog ) {
vsyslog ( prio , format , ap ) ;
} else {
2023-09-24 23:56:46 +03:00
if ( _debug_level ) {
# define _NSEC_PER_SEC (1000000000LL)
# ifdef HAVE_REALTIME
struct timespec mono_time = { 0 } ;
if ( clock_gettime ( CLOCK_MONOTONIC , & mono_time ) = = 0 )
now = mono_time . tv_sec * _NSEC_PER_SEC + mono_time . tv_nsec ;
else
# endif
now = time ( NULL ) * _NSEC_PER_SEC ;
if ( ! _start )
_start = now ;
now - = _start ;
now_nsec = now % _NSEC_PER_SEC ;
now / = _NSEC_PER_SEC ;
fprintf ( stream , " [%2lld:%02lld.%06lld] %8x:%-6s%s " ,
now / 60 , now % 60 , now_nsec / 1000 ,
2016-11-03 14:01:01 +03:00
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
( int ) pthread_self ( ) , subsys ,
( _debug_level > 3 ) ? " " : indent ) ;
2023-09-24 23:56:46 +03:00
}
2015-10-10 17:40:52 +03:00
if ( _debug_level > 3 )
fprintf ( stream , " %28s:%4d %s " , file , line , indent ) ;
vfprintf ( stream , _ ( format ) , ap ) ;
fputc ( ' \n ' , stream ) ;
fflush ( stream ) ;
}
pthread_mutex_unlock ( & _log_mutex ) ;
2016-11-02 16:40:12 +03:00
if ( _abort_on_internal_errors < 0 )
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors =
strcmp ( getenv ( " DM_ABORT_ON_INTERNAL_ERRORS " ) ? : " 0 " , " 0 " ) ;
if ( _abort_on_internal_errors & &
! strncmp ( format , INTERNAL_ERROR , sizeof ( INTERNAL_ERROR ) - 1 ) )
abort ( ) ;
2015-10-10 17:40:52 +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
{
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 ) {
2015-10-09 22:57:48 +03:00
log_error ( " Malformed reply from dmeventd '%s'. " ,
2007-02-02 20:08:51 +03:00
msg . data ) ;
2018-06-08 15:40:53 +03:00
free ( msg . data ) ;
2007-02-02 20:08:51 +03:00
return - EIO ;
}
* timeout = atoi ( p ) ;
}
2018-06-08 15:40:53 +03:00
free ( msg . data ) ;
2014-03-24 12:20:18 +04:00
2005-12-02 18:39:16 +03:00
return ret ;
}
2007-01-12 00:54:53 +03:00
# endif