2012-02-28 22:35:04 +04:00
/*
* Copyright ( C ) 2011 - 2012 Red Hat , Inc .
*
* This file is part of LVM2 .
*
* 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
*/
2012-09-26 16:44:03 +04:00
# include "daemon-io.h"
2012-02-28 22:35:04 +04:00
# include "daemon-client.h"
2012-09-26 16:44:03 +04:00
# include "dm-logging.h"
2012-02-28 22:35:04 +04:00
2011-06-14 06:34:18 +04:00
# include <sys/un.h>
# include <sys/socket.h>
# include <string.h>
# include <stdio.h>
2011-08-31 16:18:40 +04:00
# include <unistd.h>
2011-06-14 06:34:18 +04:00
# include <assert.h>
2011-06-27 17:14:53 +04:00
# include <errno.h> // ENOMEM
2011-06-14 06:34:18 +04:00
2013-01-05 03:29:59 +04:00
daemon_handle daemon_open ( daemon_info i )
{
2012-02-26 12:46:28 +04:00
daemon_handle h = { . protocol_version = 0 , . error = 0 } ;
2012-12-14 19:38:07 +04:00
daemon_reply r = { 0 } ;
2012-06-21 23:19:28 +04:00
struct sockaddr_un sockaddr = { . sun_family = AF_UNIX } ;
2011-09-17 18:49:18 +04:00
2013-01-05 03:29:59 +04:00
log_debug ( " %s: Opening daemon socket to %s for protocol %s version %d. " ,
i . socket , i . path , i . protocol , i . protocol_version ) ;
if ( ( h . socket_fd = socket ( PF_UNIX , SOCK_STREAM /* | SOCK_NONBLOCK */ , 0 ) ) < 0 ) {
h . error = errno ;
log_sys_error ( " socket " , i . socket ) ;
2011-06-14 06:34:18 +04:00
goto error ;
2013-01-05 03:29:59 +04:00
}
2012-02-26 12:46:28 +04:00
2012-04-27 13:52:33 +04:00
if ( ! dm_strncpy ( sockaddr . sun_path , i . socket , sizeof ( sockaddr . sun_path ) ) ) {
2013-01-05 03:29:59 +04:00
log_error ( " %s: Daemon socket path too long. " , i . socket ) ;
2012-04-27 13:52:33 +04:00
goto error ;
}
2012-06-21 23:19:28 +04:00
2013-01-05 03:29:59 +04:00
if ( connect ( h . socket_fd , ( struct sockaddr * ) & sockaddr , sizeof ( sockaddr ) ) ) {
h . error = errno ;
log_sys_error ( " connect " , i . socket ) ;
2011-06-14 06:34:18 +04:00
goto error ;
2013-01-05 03:29:59 +04:00
}
2012-02-24 03:52:11 +04:00
2013-01-05 03:29:59 +04:00
log_debug ( " Sending daemon %s: hello " , i . path ) ;
2012-02-24 04:02:54 +04:00
r = daemon_send_simple ( h , " hello " , NULL ) ;
2013-01-05 03:29:59 +04:00
if ( r . error | | strcmp ( daemon_reply_str ( r , " response " , " unknown " ) , " OK " ) ) {
h . error = r . error ;
log_error ( " Daemon %s returned error %d " , i . path , r . error ) ;
2012-02-24 03:52:11 +04:00
goto error ;
2013-01-05 03:29:59 +04:00
}
2012-02-24 03:52:11 +04:00
2013-01-05 03:29:59 +04:00
/* Check protocol and version matches */
2012-02-24 03:52:11 +04:00
h . protocol = daemon_reply_str ( r , " protocol " , NULL ) ;
if ( h . protocol )
h . protocol = dm_strdup ( h . protocol ) ; /* keep around */
h . protocol_version = daemon_reply_int ( r , " version " , 0 ) ;
2013-01-05 03:29:59 +04:00
if ( i . protocol & & ( ! h . protocol | | strcmp ( h . protocol , i . protocol ) ) ) {
log_error ( " Daemon %s: requested protocol %s != %s " ,
i . path , i . protocol , h . protocol ? : " " ) ;
2012-02-24 03:52:11 +04:00
goto error ;
2013-01-05 03:29:59 +04:00
}
if ( i . protocol_version & & h . protocol_version ! = i . protocol_version ) {
log_error ( " Daemon %s: requested protocol version %d != %d " ,
i . path , i . protocol_version , h . protocol_version ) ;
2012-02-24 03:52:11 +04:00
goto error ;
2013-01-05 03:29:59 +04:00
}
2012-02-24 03:52:11 +04:00
daemon_reply_destroy ( r ) ;
2011-06-14 06:34:18 +04:00
return h ;
2012-02-26 12:46:28 +04:00
2011-06-14 06:34:18 +04:00
error :
if ( h . socket_fd > = 0 )
2012-03-02 01:12:37 +04:00
if ( close ( h . socket_fd ) )
2012-09-26 15:11:13 +04:00
log_sys_error ( " close " , " daemon_open " ) ;
2012-02-24 03:52:11 +04:00
if ( r . cft )
daemon_reply_destroy ( r ) ;
2011-06-14 06:34:18 +04:00
h . socket_fd = - 1 ;
return h ;
}
daemon_reply daemon_send ( daemon_handle h , daemon_request rq )
{
2012-10-12 12:15:30 +04:00
struct buffer buffer ;
2012-12-14 19:38:07 +04:00
daemon_reply reply = { 0 } ;
2011-06-14 06:34:18 +04:00
assert ( h . socket_fd > = 0 ) ;
2012-10-12 12:15:30 +04:00
buffer = rq . buffer ;
2011-06-14 06:34:18 +04:00
2012-10-11 16:17:17 +04:00
if ( ! buffer . mem )
2012-12-15 00:36:27 +04:00
if ( ! dm_config_write_node ( rq . cft - > root , buffer_line , & buffer ) ) {
reply . error = ENOMEM ;
return reply ;
}
2011-06-14 06:34:18 +04:00
2012-10-11 16:17:17 +04:00
assert ( buffer . mem ) ;
if ( ! buffer_write ( h . socket_fd , & buffer ) )
2012-02-26 12:46:28 +04:00
reply . error = errno ;
2012-10-11 16:17:17 +04:00
if ( buffer_read ( h . socket_fd , & reply . buffer ) ) {
reply . cft = dm_config_from_string ( reply . buffer . mem ) ;
2012-09-20 01:30:16 +04:00
if ( ! reply . cft )
reply . error = EPROTO ;
2011-06-14 06:34:18 +04:00
} else
2012-02-26 12:46:28 +04:00
reply . error = errno ;
2011-06-14 06:34:18 +04:00
2012-10-11 16:17:17 +04:00
if ( buffer . mem ! = rq . buffer . mem )
buffer_destroy ( & buffer ) ;
2012-10-08 20:35:30 +04:00
2011-06-14 06:34:18 +04:00
return reply ;
}
2011-06-27 17:58:11 +04:00
void daemon_reply_destroy ( daemon_reply r ) {
if ( r . cft )
2011-08-31 16:18:40 +04:00
dm_config_destroy ( r . cft ) ;
2012-10-11 16:17:17 +04:00
buffer_destroy ( & r . buffer ) ;
2011-06-27 17:58:11 +04:00
}
2012-08-11 12:33:53 +04:00
daemon_reply daemon_send_simple_v ( daemon_handle h , const char * id , va_list ap )
2011-06-27 17:14:53 +04:00
{
2012-12-14 19:38:07 +04:00
static const daemon_reply err = { . error = ENOMEM } ;
2011-10-31 01:58:59 +04:00
daemon_request rq = { . cft = NULL } ;
2011-09-17 18:49:18 +04:00
daemon_reply repl ;
2012-10-13 21:19:50 +04:00
if ( ! buffer_append_f ( & rq . buffer , " request = %s " , id , NULL ) | |
! buffer_append_vf ( & rq . buffer , ap ) ) {
buffer_destroy ( & rq . buffer ) ;
2011-06-27 17:14:53 +04:00
return err ;
2012-10-13 21:19:50 +04:00
}
2011-06-27 17:14:53 +04:00
2011-09-17 18:49:18 +04:00
repl = daemon_send ( h , rq ) ;
2012-10-11 16:17:17 +04:00
buffer_destroy ( & rq . buffer ) ;
2012-02-27 15:49:16 +04:00
2011-06-27 17:14:53 +04:00
return repl ;
}
2012-08-11 12:33:53 +04:00
daemon_reply daemon_send_simple ( daemon_handle h , const char * id , . . . )
{
2012-10-12 12:15:30 +04:00
daemon_reply r ;
2012-08-11 12:33:53 +04:00
va_list ap ;
2012-10-12 12:15:30 +04:00
2012-08-11 12:33:53 +04:00
va_start ( ap , id ) ;
2012-10-12 12:15:30 +04:00
r = daemon_send_simple_v ( h , id , ap ) ;
2012-08-11 12:33:53 +04:00
va_end ( ap ) ;
2012-10-12 12:15:30 +04:00
2012-08-11 12:33:53 +04:00
return r ;
}
2011-06-27 17:14:53 +04:00
void daemon_close ( daemon_handle h )
{
2012-02-24 03:52:11 +04:00
dm_free ( ( char * ) h . protocol ) ;
2011-06-14 06:34:18 +04:00
}
2012-08-11 12:33:53 +04:00
daemon_request daemon_request_make ( const char * id )
{
daemon_request r ;
r . cft = NULL ;
2012-10-11 16:17:17 +04:00
buffer_init ( & r . buffer ) ;
2012-08-11 12:33:53 +04:00
if ( ! ( r . cft = dm_config_create ( ) ) )
goto bad ;
if ( ! ( r . cft - > root = make_text_node ( r . cft , " request " , id , NULL , NULL ) ) )
goto bad ;
return r ;
bad :
if ( r . cft )
dm_config_destroy ( r . cft ) ;
r . cft = NULL ;
return r ;
}
int daemon_request_extend_v ( daemon_request r , va_list ap )
{
if ( ! r . cft )
return 0 ;
if ( ! config_make_nodes_v ( r . cft , NULL , r . cft - > root , ap ) )
return 0 ;
return 1 ;
}
int daemon_request_extend ( daemon_request r , . . . )
{
2012-10-12 12:15:30 +04:00
int res ;
2012-08-11 12:33:53 +04:00
va_list ap ;
2012-10-12 12:15:30 +04:00
2012-08-11 12:33:53 +04:00
va_start ( ap , r ) ;
2012-10-12 12:15:30 +04:00
res = daemon_request_extend_v ( r , ap ) ;
2012-08-11 12:33:53 +04:00
va_end ( ap ) ;
2012-10-12 12:15:30 +04:00
2012-08-11 12:33:53 +04:00
return res ;
}
void daemon_request_destroy ( daemon_request r ) {
if ( r . cft )
dm_config_destroy ( r . cft ) ;
2012-10-11 16:17:17 +04:00
buffer_destroy ( & r . buffer ) ;
2012-08-11 12:33:53 +04:00
}