2006-10-04 12:22:16 +04:00
/*
* Copyright ( C ) 2002 - 2004 Sistina Software , Inc . All rights reserved .
2010-04-20 18:07:37 +04:00
* Copyright ( C ) 2004 - 2010 Red Hat , Inc . All rights reserved .
2006-10-04 12:22:16 +04:00
*
* 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 General Public License v .2 .
*
* You should have received a copy of the GNU 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
*/
/*
2010-04-20 18:07:37 +04:00
* Send a command to a running clvmd from the command - line
2006-10-04 12:22:16 +04:00
*/
2010-06-21 19:56:57 +04:00
# include "clvmd-common.h"
# include "clvm.h"
# include "refresh_clvmd.h"
2008-11-04 19:41:47 +03:00
2006-10-04 12:22:16 +04:00
# include <stddef.h>
# include <sys/socket.h>
# include <sys/un.h>
typedef struct lvm_response {
char node [ 255 ] ;
char * response ;
int status ;
int len ;
} lvm_response_t ;
/*
* This gets stuck at the start of memory we allocate so we
* can sanity - check it at deallocation time
*/
# define LVM_SIGNATURE 0x434C564D
static int _clvmd_sock = - 1 ;
2007-08-17 15:51:23 +04:00
/* Open connection to the clvm daemon */
2006-10-04 12:22:16 +04:00
static int _open_local_sock ( void )
{
int local_socket ;
struct sockaddr_un sockaddr ;
/* Open local socket */
if ( ( local_socket = socket ( PF_UNIX , SOCK_STREAM , 0 ) ) < 0 ) {
fprintf ( stderr , " Local socket creation failed: %s " , strerror ( errno ) ) ;
return - 1 ;
}
memset ( & sockaddr , 0 , sizeof ( sockaddr ) ) ;
memcpy ( sockaddr . sun_path , CLVMD_SOCKNAME , sizeof ( CLVMD_SOCKNAME ) ) ;
sockaddr . sun_family = AF_UNIX ;
if ( connect ( local_socket , ( struct sockaddr * ) & sockaddr ,
sizeof ( sockaddr ) ) ) {
int saved_errno = errno ;
fprintf ( stderr , " connect() failed on local socket: %s \n " ,
strerror ( errno ) ) ;
if ( close ( local_socket ) )
return - 1 ;
errno = saved_errno ;
return - 1 ;
}
return local_socket ;
}
/* Send a request and return the status */
2010-04-20 18:07:37 +04:00
static int _send_request ( const char * inbuf , int inlen , char * * retbuf , int no_response )
2006-10-04 12:22:16 +04:00
{
char outbuf [ PIPE_BUF ] ;
struct clvm_header * outheader = ( struct clvm_header * ) outbuf ;
int len ;
int off ;
int buflen ;
int err ;
/* Send it to CLVMD */
rewrite :
if ( ( err = write ( _clvmd_sock , inbuf , inlen ) ) ! = inlen ) {
if ( err = = - 1 & & errno = = EINTR )
goto rewrite ;
fprintf ( stderr , " Error writing data to clvmd: %s " , strerror ( errno ) ) ;
return 0 ;
}
2010-04-20 18:07:37 +04:00
if ( no_response )
return 1 ;
2006-10-04 12:22:16 +04:00
/* Get the response */
reread :
if ( ( len = read ( _clvmd_sock , outbuf , sizeof ( struct clvm_header ) ) ) < 0 ) {
if ( errno = = EINTR )
goto reread ;
fprintf ( stderr , " Error reading data from clvmd: %s " , strerror ( errno ) ) ;
return 0 ;
}
if ( len = = 0 ) {
fprintf ( stderr , " EOF reading CLVMD " ) ;
errno = ENOTCONN ;
return 0 ;
}
/* Allocate buffer */
buflen = len + outheader - > arglen ;
* retbuf = dm_malloc ( buflen ) ;
if ( ! * retbuf ) {
errno = ENOMEM ;
return 0 ;
}
/* Copy the header */
memcpy ( * retbuf , outbuf , len ) ;
outheader = ( struct clvm_header * ) * retbuf ;
/* Read the returned values */
off = 1 ; /* we've already read the first byte */
while ( off < = outheader - > arglen & & len > 0 ) {
len = read ( _clvmd_sock , outheader - > args + off ,
buflen - off - offsetof ( struct clvm_header , args ) ) ;
if ( len > 0 )
off + = len ;
}
/* Was it an error ? */
if ( outheader - > status ! = 0 ) {
errno = outheader - > status ;
/* Only return an error here if there are no node-specific
errors present in the message that might have more detail */
if ( ! ( outheader - > flags & CLVMD_FLAG_NODEERRS ) ) {
fprintf ( stderr , " cluster request failed: %s \n " , strerror ( errno ) ) ;
return 0 ;
}
}
return 1 ;
}
/* Build the structure header and parse-out wildcard node names */
static void _build_header ( struct clvm_header * head , int cmd , const char * node ,
int len )
{
head - > cmd = cmd ;
head - > status = 0 ;
head - > flags = 0 ;
head - > clientid = 0 ;
head - > arglen = len ;
if ( node ) {
/*
* Allow a couple of special node names :
* " * " for all nodes ,
* " . " for the local node only
*/
if ( strcmp ( node , " * " ) = = 0 ) {
head - > node [ 0 ] = ' \0 ' ;
} else if ( strcmp ( node , " . " ) = = 0 ) {
head - > node [ 0 ] = ' \0 ' ;
head - > flags = CLVMD_FLAG_LOCAL ;
} else
strcpy ( head - > node , node ) ;
} else
head - > node [ 0 ] = ' \0 ' ;
}
/*
* Send a message to a ( or all ) node ( s ) in the cluster and wait for replies
*/
static int _cluster_request ( char cmd , const char * node , void * data , int len ,
2010-04-20 18:07:37 +04:00
lvm_response_t * * response , int * num , int no_response )
2006-10-04 12:22:16 +04:00
{
char outbuf [ sizeof ( struct clvm_header ) + len + strlen ( node ) + 1 ] ;
char * inptr ;
char * retbuf = NULL ;
int status ;
int i ;
int num_responses = 0 ;
struct clvm_header * head = ( struct clvm_header * ) outbuf ;
lvm_response_t * rarray ;
* num = 0 ;
if ( _clvmd_sock = = - 1 )
_clvmd_sock = _open_local_sock ( ) ;
if ( _clvmd_sock = = - 1 )
return 0 ;
_build_header ( head , cmd , node , len ) ;
memcpy ( head - > node + strlen ( head - > node ) + 1 , data , len ) ;
status = _send_request ( outbuf , sizeof ( struct clvm_header ) +
2010-04-20 18:07:37 +04:00
strlen ( head - > node ) + len , & retbuf , no_response ) ;
if ( ! status | | no_response )
2006-10-04 12:22:16 +04:00
goto out ;
/* Count the number of responses we got */
head = ( struct clvm_header * ) retbuf ;
inptr = head - > args ;
while ( inptr [ 0 ] ) {
num_responses + + ;
inptr + = strlen ( inptr ) + 1 ;
inptr + = sizeof ( int ) ;
inptr + = strlen ( inptr ) + 1 ;
}
/*
* Allocate response array .
* With an extra pair of INTs on the front to sanity
* check the pointer when we are given it back to free
*/
2006-12-02 02:10:26 +03:00
* response = dm_malloc ( sizeof ( lvm_response_t ) * num_responses +
2006-10-04 12:22:16 +04:00
sizeof ( int ) * 2 ) ;
2006-12-02 02:10:26 +03:00
if ( ! * response ) {
2006-10-04 12:22:16 +04:00
errno = ENOMEM ;
status = 0 ;
goto out ;
}
rarray = * response ;
/* Unpack the response into an lvm_response_t array */
inptr = head - > args ;
i = 0 ;
while ( inptr [ 0 ] ) {
strcpy ( rarray [ i ] . node , inptr ) ;
inptr + = strlen ( inptr ) + 1 ;
memcpy ( & rarray [ i ] . status , inptr , sizeof ( int ) ) ;
inptr + = sizeof ( int ) ;
rarray [ i ] . response = dm_malloc ( strlen ( inptr ) + 1 ) ;
if ( rarray [ i ] . response = = NULL ) {
/* Free up everything else and return error */
int j ;
for ( j = 0 ; j < i ; j + + )
dm_free ( rarray [ i ] . response ) ;
2006-12-02 02:10:26 +03:00
free ( * response ) ;
2006-10-04 12:22:16 +04:00
errno = ENOMEM ;
status = - 1 ;
goto out ;
}
strcpy ( rarray [ i ] . response , inptr ) ;
rarray [ i ] . len = strlen ( inptr ) ;
inptr + = strlen ( inptr ) + 1 ;
i + + ;
}
* num = num_responses ;
* response = rarray ;
out :
if ( retbuf )
dm_free ( retbuf ) ;
return status ;
}
/* Free reply array */
2006-12-02 02:10:26 +03:00
static int _cluster_free_request ( lvm_response_t * response , int num )
2006-10-04 12:22:16 +04:00
{
int i ;
for ( i = 0 ; i < num ; i + + ) {
dm_free ( response [ i ] . response ) ;
}
2006-12-02 02:10:26 +03:00
dm_free ( response ) ;
2006-10-04 12:22:16 +04:00
return 1 ;
}
2010-04-20 18:07:37 +04:00
int refresh_clvmd ( int all_nodes )
2006-10-04 12:22:16 +04:00
{
int num_responses ;
char args [ 1 ] ; // No args really.
2010-07-02 01:46:09 +04:00
lvm_response_t * response = NULL ;
2006-10-04 12:22:16 +04:00
int saved_errno ;
int status ;
int i ;
2010-04-20 18:07:37 +04:00
status = _cluster_request ( CLVMD_CMD_REFRESH , all_nodes ? " * " : " . " , args , 0 , & response , & num_responses , 0 ) ;
2006-10-04 12:22:16 +04:00
/* If any nodes were down then display them and return an error */
for ( i = 0 ; i < num_responses ; i + + ) {
if ( response [ i ] . status = = EHOSTDOWN ) {
fprintf ( stderr , " clvmd not running on node %s " ,
response [ i ] . node ) ;
status = 0 ;
errno = response [ i ] . status ;
} else if ( response [ i ] . status ) {
fprintf ( stderr , " Error resetting node %s: %s " ,
response [ i ] . node ,
response [ i ] . response [ 0 ] ?
response [ i ] . response :
strerror ( response [ i ] . status ) ) ;
status = 0 ;
errno = response [ i ] . status ;
}
}
saved_errno = errno ;
2006-12-02 02:10:26 +03:00
_cluster_free_request ( response , num_responses ) ;
2006-10-04 12:22:16 +04:00
errno = saved_errno ;
return status ;
}
2007-08-17 15:51:23 +04:00
2010-04-20 18:07:37 +04:00
int restart_clvmd ( int all_nodes )
{
2010-06-21 14:45:15 +04:00
int dummy , status ;
status = _cluster_request ( CLVMD_CMD_RESTART , all_nodes ? " * " : " . " , NULL , 0 , NULL , & dummy , 1 ) ;
/*
* FIXME : we cannot receive response , clvmd re - exec before it .
* but also should not close socket too early ( the whole rq is dropped then ) .
* FIXME : This should be handled this way :
* - client waits for RESTART ack ( and socket close )
* - server restarts
* - client checks that server is ready again ( VERSION command ? )
*/
usleep ( 500000 ) ;
return status ;
2010-04-20 18:07:37 +04:00
}
2007-08-17 15:51:23 +04:00
int debug_clvmd ( int level , int clusterwide )
{
int num_responses ;
char args [ 1 ] ;
const char * nodes ;
2010-06-07 17:52:52 +04:00
lvm_response_t * response = NULL ;
2007-08-17 15:51:23 +04:00
int saved_errno ;
int status ;
int i ;
args [ 0 ] = level ;
if ( clusterwide )
nodes = " * " ;
else
nodes = " . " ;
2010-04-20 18:07:37 +04:00
status = _cluster_request ( CLVMD_CMD_SET_DEBUG , nodes , args , 1 , & response , & num_responses , 0 ) ;
2007-08-17 15:51:23 +04:00
/* If any nodes were down then display them and return an error */
for ( i = 0 ; i < num_responses ; i + + ) {
if ( response [ i ] . status = = EHOSTDOWN ) {
fprintf ( stderr , " clvmd not running on node %s " ,
response [ i ] . node ) ;
status = 0 ;
errno = response [ i ] . status ;
} else if ( response [ i ] . status ) {
fprintf ( stderr , " Error setting debug on node %s: %s " ,
response [ i ] . node ,
response [ i ] . response [ 0 ] ?
response [ i ] . response :
strerror ( response [ i ] . status ) ) ;
status = 0 ;
errno = response [ i ] . status ;
}
}
saved_errno = errno ;
_cluster_free_request ( response , num_responses ) ;
errno = saved_errno ;
return status ;
}