2005-10-17 21:56:27 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2011-01-13 17:51:32 +03:00
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
2005-10-17 21:56:27 +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
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2005-10-17 21:56:27 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2005-10-17 21:56:27 +04:00
* 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-10-17 21:56:27 +04:00
*/
2018-05-14 12:30:20 +03:00
# include "lib/misc/lib.h"
# include "lib/device/device.h"
# include "lib/locking/locking.h"
# include "lib/misc/lvm-exec.h"
# include "lib/commands/toolcontext.h"
2005-10-17 21:56:27 +04:00
# include <unistd.h>
# include <sys/wait.h>
2009-02-24 18:48:00 +03:00
/*
* Create verbose string with list of parameters
*/
2009-02-28 02:40:11 +03:00
static char * _verbose_args ( const char * const argv [ ] , char * buf , size_t sz )
2009-02-24 18:48:00 +03:00
{
int pos = 0 ;
2009-02-28 02:40:11 +03:00
int len ;
unsigned i ;
2009-02-24 18:48:00 +03:00
2009-02-28 02:40:11 +03:00
buf [ 0 ] = ' \0 ' ;
for ( i = 0 ; argv [ i ] ; i + + ) {
if ( ( len = dm_snprintf ( buf + pos , sz - pos ,
2012-03-03 02:58:23 +04:00
" %s " , argv [ i ] ) ) < 0 )
2009-02-28 02:40:11 +03:00
/* Truncated */
break ;
2009-02-24 18:48:00 +03:00
pos + = len ;
}
return buf ;
}
2005-10-17 21:56:27 +04:00
/*
* Execute and wait for external command
*/
2011-01-13 17:51:32 +03:00
int exec_cmd ( struct cmd_context * cmd , const char * const argv [ ] ,
int * rstatus , int sync_needed )
2005-10-17 21:56:27 +04:00
{
pid_t pid ;
2021-09-10 23:32:26 +03:00
int status = 0 ;
2009-02-28 02:40:11 +03:00
char buf [ PATH_MAX * 2 ] ;
2005-10-17 21:56:27 +04:00
2015-11-08 19:18:23 +03:00
if ( rstatus )
* rstatus = - 1 ;
2014-04-04 23:15:17 +04:00
if ( ! argv [ 0 ] ) {
log_error ( INTERNAL_ERROR " Missing command. " ) ;
return 0 ;
}
2011-01-13 17:51:32 +03:00
if ( sync_needed )
2015-06-30 20:54:38 +03:00
/* Flush ops and reset dm cookie */
if ( ! sync_local_dev_names ( cmd ) ) {
log_error ( " Failed to sync local device names before forking. " ) ;
return 0 ;
}
2011-01-10 22:31:02 +03:00
2012-03-03 02:58:23 +04:00
log_verbose ( " Executing:%s " , _verbose_args ( argv , buf , sizeof ( buf ) ) ) ;
2011-09-19 16:48:02 +04:00
2005-10-17 21:56:27 +04:00
if ( ( pid = fork ( ) ) = = - 1 ) {
2013-08-06 16:26:00 +04:00
log_sys_error ( " fork " , " " ) ;
2005-10-17 21:56:27 +04:00
return 0 ;
}
if ( ! pid ) {
/* Child */
2009-02-28 03:54:06 +03:00
reset_locking ( ) ;
/* FIXME Fix effect of reset_locking on cache then include this */
/* destroy_toolcontext(cmd); */
2005-10-17 21:56:27 +04:00
/* FIXME Use execve directly */
2014-04-04 23:15:17 +04:00
execvp ( argv [ 0 ] , ( char * * ) argv ) ;
2009-02-24 18:48:00 +03:00
log_sys_error ( " execvp " , argv [ 0 ] ) ;
2009-07-14 01:26:41 +04:00
_exit ( errno ) ;
2005-10-17 21:56:27 +04:00
}
/* Parent */
if ( wait4 ( pid , & status , 0 , NULL ) ! = pid ) {
log_error ( " wait4 child process %u failed: %s " , pid ,
strerror ( errno ) ) ;
return 0 ;
}
if ( ! WIFEXITED ( status ) ) {
log_error ( " Child %u exited abnormally " , pid ) ;
return 0 ;
}
if ( WEXITSTATUS ( status ) ) {
2010-11-01 17:17:35 +03:00
if ( rstatus ) {
* rstatus = WEXITSTATUS ( status ) ;
2011-09-19 22:38:43 +04:00
log_verbose ( " %s failed: %u " , argv [ 0 ] , * rstatus ) ;
2010-11-01 17:17:35 +03:00
} else
log_error ( " %s failed: %u " , argv [ 0 ] , WEXITSTATUS ( status ) ) ;
2005-10-17 21:56:27 +04:00
return 0 ;
}
2010-11-01 17:17:35 +03:00
if ( rstatus )
* rstatus = 0 ;
2005-10-17 21:56:27 +04:00
return 1 ;
}
2013-08-06 16:27:37 +04:00
static int _reopen_fd_to_null ( int fd )
{
int null_fd ;
2013-08-15 14:23:49 +04:00
int r = 0 ;
2013-08-06 16:27:37 +04:00
if ( ( null_fd = open ( " /dev/null " , O_RDWR ) ) = = - 1 ) {
log_sys_error ( " open " , " /dev/null " ) ;
return 0 ;
}
if ( close ( fd ) ) {
log_sys_error ( " close " , " " ) ;
2013-08-15 14:23:49 +04:00
goto out ;
2013-08-06 16:27:37 +04:00
}
if ( dup2 ( null_fd , fd ) = = - 1 ) {
log_sys_error ( " dup2 " , " " ) ;
2013-08-15 14:23:49 +04:00
goto out ;
2013-08-06 16:27:37 +04:00
}
2013-08-15 14:23:49 +04:00
r = 1 ;
out :
2013-08-06 16:27:37 +04:00
if ( close ( null_fd ) ) {
log_sys_error ( " dup2 " , " " ) ;
return 0 ;
}
2013-08-15 14:23:49 +04:00
return r ;
2013-08-06 16:27:37 +04:00
}
FILE * pipe_open ( struct cmd_context * cmd , const char * const argv [ ] ,
int sync_needed , struct pipe_data * pdata )
{
int pipefd [ 2 ] ;
char buf [ PATH_MAX * 2 ] ;
if ( sync_needed )
2015-06-30 20:54:38 +03:00
/* Flush ops and reset dm cookie */
if ( ! sync_local_dev_names ( cmd ) ) {
log_error ( " Failed to sync local device names before forking. " ) ;
return 0 ;
}
2013-08-06 16:27:37 +04:00
if ( pipe ( pipefd ) ) {
log_sys_error ( " pipe " , " " ) ;
return 0 ;
}
log_verbose ( " Piping:%s " , _verbose_args ( argv , buf , sizeof ( buf ) ) ) ;
if ( ( pdata - > pid = fork ( ) ) = = - 1 ) {
2024-06-16 16:15:44 +03:00
log_sys_error ( " fork " , " " ) ;
if ( close ( pipefd [ 0 ] ) )
log_sys_debug ( " close " , " STDOUT " ) ;
if ( close ( pipefd [ 1 ] ) )
log_sys_debug ( " close " , " STDIN " ) ;
2013-08-06 16:27:37 +04:00
return 0 ;
}
if ( pdata - > pid = = 0 ) {
/* Child -> writer, convert pipe[0] to STDOUT */
if ( ! _reopen_fd_to_null ( STDIN_FILENO ) )
stack ;
else if ( close ( pipefd [ 0 /*read*/ ] ) )
log_sys_error ( " close " , " pipe[0] " ) ;
else if ( close ( STDOUT_FILENO ) )
log_sys_error ( " close " , " STDOUT " ) ;
else if ( dup2 ( pipefd [ 1 /*write*/ ] , STDOUT_FILENO ) = = - 1 )
log_sys_error ( " dup2 " , " STDOUT " ) ;
else if ( close ( pipefd [ 1 ] ) )
log_sys_error ( " close " , " pipe[1] " ) ;
else if ( argv [ 0 ] ) {
execvp ( argv [ 0 ] , ( char * * ) argv ) ;
log_sys_error ( " execvp " , argv [ 0 ] ) ;
}
_exit ( errno ) ;
}
/* Parent -> reader */
if ( close ( pipefd [ 1 /*write*/ ] ) ) {
log_sys_error ( " close " , " STDOUT " ) ;
return NULL ;
}
if ( ! ( pdata - > fp = fdopen ( pipefd [ 0 /*read*/ ] , " r " ) ) ) {
log_sys_error ( " fdopen " , " STDIN " ) ;
if ( close ( pipefd [ 0 ] ) )
log_sys_error ( " close " , " STDIN " ) ;
return NULL ; /* FIXME: kill */
}
return pdata - > fp ;
}
int pipe_close ( struct pipe_data * pdata )
{
int status ;
if ( fclose ( pdata - > fp ) )
log_sys_error ( " fclose " , " STDIN " ) ;
if ( waitpid ( pdata - > pid , & status , 0 ) ! = pdata - > pid ) {
log_sys_error ( " waitpid " , " " ) ;
return 0 ;
}
return ( status = = 0 ) ? 1 : 0 ;
}
2023-07-16 18:35:20 +03:00
int prepare_exec_args ( struct cmd_context * cmd ,
const char * argv [ ] , int * argc , int options_id )
{
const struct dm_config_value * cv ;
const struct dm_config_node * cn ;
if ( ! ( cn = find_config_tree_array ( cmd , options_id , NULL ) ) ) {
log_error ( INTERNAL_ERROR " Unable to find configuration for %s options. " ,
argv [ 0 ] ) ;
return 0 ;
}
for ( cv = cn - > v ; cv ; cv = cv - > next ) {
if ( * argc > = DEFAULT_MAX_EXEC_ARGS ) {
log_error ( " Too many options for %s command. " , argv [ 0 ] ) ;
return 0 ;
}
if ( cv - > type ! = DM_CFG_STRING ) {
log_error ( " Invalid string in config file: "
" global/%s_options. " , argv [ 0 ] ) ;
return 0 ;
}
if ( cv - > v . str [ 0 ] )
argv [ + + ( * argc ) ] = cv - > v . str ;
}
return 1 ;
}