2001-09-25 16:49:28 +04:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2001-09-25 16:49:28 +04:00
*
2004-03-30 23:35:44 +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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-09-25 16:49:28 +04:00
*/
2007-02-14 19:51:48 +03:00
# include "tools.h"
2015-07-06 19:30:18 +03:00
2004-03-26 15:00:24 +03:00
# include "lvm2cmdline.h"
2002-11-18 17:04:08 +03:00
int main ( int argc , char * * argv )
{
2008-12-18 08:27:17 +03:00
return lvm2_main ( argc , argv ) ;
2002-11-18 17:04:08 +03:00
}
2007-02-14 19:51:48 +03:00
# ifdef READLINE_SUPPORT
# include <readline / readline.h>
# include <readline / history.h>
# ifndef HAVE_RL_COMPLETION_MATCHES
# define rl_completion_matches(a, b) completion_matches((char *)a, b)
2014-03-06 19:04:19 +04:00
# define rl_completion_func_t CPPFunction
2007-02-14 19:51:48 +03:00
# endif
static struct cmdline_context * _cmdline ;
/* List matching commands */
static char * _list_cmds ( const char * text , int state )
{
static int i = 0 ;
static size_t len = 0 ;
/* Initialise if this is a new completion attempt */
if ( ! state ) {
i = 0 ;
len = strlen ( text ) ;
}
while ( i < _cmdline - > num_commands )
if ( ! strncmp ( text , _cmdline - > commands [ i + + ] . name , len ) )
return strdup ( _cmdline - > commands [ i - 1 ] . name ) ;
return NULL ;
}
/* List matching arguments */
static char * _list_args ( const char * text , int state )
{
static int match_no = 0 ;
static size_t len = 0 ;
static struct command * com ;
/* Initialise if this is a new completion attempt */
if ( ! state ) {
char * s = rl_line_buffer ;
2012-02-08 15:36:18 +04:00
int j ;
2007-02-14 19:51:48 +03:00
match_no = 0 ;
com = NULL ;
len = strlen ( text ) ;
/* Find start of first word in line buffer */
while ( isspace ( * s ) )
s + + ;
/* Look for word in list of commands */
for ( j = 0 ; j < _cmdline - > num_commands ; j + + ) {
const char * p ;
char * q = s ;
p = _cmdline - > commands [ j ] . name ;
while ( * p = = * q ) {
p + + ;
q + + ;
}
if ( ( ! * p ) & & * q = = ' ' ) {
com = _cmdline - > commands + j ;
break ;
}
}
}
2010-10-25 16:57:00 +04:00
if ( ! com )
return NULL ;
2007-02-14 19:51:48 +03:00
/* Short form arguments */
2013-04-13 05:26:37 +04:00
if ( len < 3 ) {
while ( match_no < com - > num_args ) {
char s [ 3 ] ;
char c ;
if ( ! ( c = ( _cmdline - > arg_props +
com - > valid_args [ match_no + + ] ) - > short_arg ) )
continue ;
sprintf ( s , " -%c " , c ) ;
if ( ! strncmp ( text , s , len ) )
return strdup ( s ) ;
}
2007-02-14 19:51:48 +03:00
}
/* Long form arguments */
if ( match_no < com - > num_args )
match_no = com - > num_args ;
while ( match_no - com - > num_args < com - > num_args ) {
const char * l ;
2010-11-11 20:29:05 +03:00
l = ( _cmdline - > arg_props +
2007-02-14 19:51:48 +03:00
com - > valid_args [ match_no + + - com - > num_args ] ) - > long_arg ;
if ( * ( l + 2 ) & & ! strncmp ( text , l , len ) )
return strdup ( l ) ;
}
return NULL ;
}
/* Custom completion function */
2008-01-31 15:19:36 +03:00
static char * * _completion ( const char * text , int start_pos ,
2010-07-09 19:34:40 +04:00
int end_pos __attribute__ ( ( unused ) ) )
2007-02-14 19:51:48 +03:00
{
char * * match_list = NULL ;
int p = 0 ;
while ( isspace ( ( int ) * ( rl_line_buffer + p ) ) )
p + + ;
/* First word should be one of our commands */
if ( start_pos = = p )
match_list = rl_completion_matches ( text , _list_cmds ) ;
else if ( * text = = ' - ' )
match_list = rl_completion_matches ( text , _list_args ) ;
/* else other args */
/* No further completion */
rl_attempted_completion_over = 1 ;
return match_list ;
}
static int _hist_file ( char * buffer , size_t size )
{
char * e = getenv ( " HOME " ) ;
if ( dm_snprintf ( buffer , size , " %s/.lvm_history " , e ) < 0 ) {
log_error ( " $HOME/.lvm_history: path too long " ) ;
return 0 ;
}
return 1 ;
}
static void _read_history ( struct cmd_context * cmd )
{
char hist_file [ PATH_MAX ] ;
if ( ! _hist_file ( hist_file , sizeof ( hist_file ) ) )
return ;
if ( read_history ( hist_file ) )
log_very_verbose ( " Couldn't read history from %s. " , hist_file ) ;
2013-06-25 14:30:34 +04:00
stifle_history ( find_config_tree_int ( cmd , shell_history_size_CFG , NULL ) ) ;
2007-02-14 19:51:48 +03:00
}
static void _write_history ( void )
{
char hist_file [ PATH_MAX ] ;
if ( ! _hist_file ( hist_file , sizeof ( hist_file ) ) )
return ;
if ( write_history ( hist_file ) )
log_very_verbose ( " Couldn't write history to %s. " , hist_file ) ;
}
2016-07-25 13:20:22 +03:00
static int _log_shell_command_status ( struct cmd_context * cmd , int ret_code )
{
log_report_t log_state ;
2016-08-03 16:37:14 +03:00
if ( ! cmd - > cmd_report . log_rh )
2016-07-25 13:20:22 +03:00
return 1 ;
log_state = log_get_report_state ( ) ;
2016-08-03 16:37:14 +03:00
return report_cmdlog ( cmd - > cmd_report . log_rh , REPORT_OBJECT_CMDLOG_NAME ,
2016-07-25 13:20:22 +03:00
log_get_report_context_name ( log_state . context ) ,
log_get_report_object_type_name ( log_state . object_type ) ,
log_state . object_name , log_state . object_id ,
log_state . object_group , log_state . object_group_id ,
ret_code = = ECMD_PROCESSED ? REPORT_OBJECT_CMDLOG_SUCCESS
: REPORT_OBJECT_CMDLOG_FAILURE ,
stored_errno ( ) , ret_code ) ;
}
2016-08-04 14:42:57 +03:00
static void _discard_log_report_content ( struct cmd_context * cmd )
{
if ( cmd - > cmd_report . log_rh )
dm_report_destroy_rows ( cmd - > cmd_report . log_rh ) ;
}
2007-02-14 19:51:48 +03:00
int lvm_shell ( struct cmd_context * cmd , struct cmdline_context * cmdline )
{
2016-07-25 13:20:22 +03:00
log_report_t saved_log_report_state = log_get_report_state ( ) ;
2016-08-04 19:15:54 +03:00
char * orig_command_log_selection = NULL ;
int is_lastlog_cmd = 0 , argc , ret ;
2007-02-14 19:51:48 +03:00
char * input = NULL , * args [ MAX_ARGS ] , * * argv ;
rl_readline_name = " lvm " ;
2014-03-06 19:04:19 +04:00
rl_attempted_completion_function = ( rl_completion_func_t * ) _completion ;
2007-02-14 19:51:48 +03:00
_read_history ( cmd ) ;
_cmdline = cmdline ;
2016-05-20 15:23:43 +03:00
cmd - > is_interactive = 1 ;
2016-08-04 14:42:57 +03:00
if ( ! report_format_init ( cmd ) )
return_ECMD_FAILED ;
2016-08-04 19:15:54 +03:00
orig_command_log_selection = dm_pool_strdup ( cmd - > libmem , find_config_tree_str ( cmd , log_command_log_selection_CFG , NULL ) ) ;
2016-07-25 13:20:22 +03:00
log_set_report_context ( LOG_REPORT_CONTEXT_SHELL ) ;
log_set_report_object_type ( LOG_REPORT_OBJECT_TYPE_CMD ) ;
2007-02-14 19:51:48 +03:00
while ( 1 ) {
2016-08-04 19:15:54 +03:00
if ( cmd - > cmd_report . log_rh ) {
/*
* If previous command was lastlog , reset log report selection to
* its original value as set by log / command_log_selection config setting .
*/
if ( is_lastlog_cmd & &
! dm_report_set_selection ( cmd - > cmd_report . log_rh , orig_command_log_selection ) )
log_error ( " Failed to reset log report selection. " ) ;
}
2016-08-04 14:42:57 +03:00
log_set_report ( cmd - > cmd_report . log_rh ) ;
2016-07-25 13:20:22 +03:00
log_set_report_object_name_and_id ( NULL , NULL ) ;
2016-08-04 14:42:57 +03:00
2007-02-14 19:51:48 +03:00
free ( input ) ;
input = readline ( " lvm> " ) ;
/* EOF */
if ( ! input ) {
2016-08-04 14:42:57 +03:00
_discard_log_report_content ( cmd ) ;
config: add silent mode
Accept -q as the short form of --quiet.
Suppress non-essential standard output if -q is given twice.
Treat log/silent in lvm.conf as equivalent to -qq.
Review all log_print messages and change some to
log_print_unless_silent.
When silent, the following commands still produce output:
dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay,
pvs, version, vgcfgrestore -l, vgdisplay, vgs.
[Needs checking.]
Non-essential messages are shifted from log level 4 to log level 5
for syslog and lvm2_log_fn purposes.
2012-08-25 23:35:48 +04:00
/* readline sends prompt to stdout */
2007-02-14 19:51:48 +03:00
printf ( " \n " ) ;
break ;
}
/* empty line */
2016-08-04 14:42:57 +03:00
if ( ! * input ) {
_discard_log_report_content ( cmd ) ;
2007-02-14 19:51:48 +03:00
continue ;
2016-08-04 14:42:57 +03:00
}
2007-02-14 19:51:48 +03:00
add_history ( input ) ;
argv = args ;
if ( lvm_split ( input , & argc , argv , MAX_ARGS ) = = MAX_ARGS ) {
2016-08-04 14:42:57 +03:00
_discard_log_report_content ( cmd ) ;
2007-02-14 19:51:48 +03:00
log_error ( " Too many arguments, sorry. " ) ;
continue ;
}
2016-08-04 14:42:57 +03:00
if ( ! argc ) {
_discard_log_report_content ( cmd ) ;
2010-07-01 15:04:58 +04:00
continue ;
2016-08-04 14:42:57 +03:00
}
2010-07-01 15:04:58 +04:00
2007-02-14 19:51:48 +03:00
if ( ! strcmp ( argv [ 0 ] , " lvm " ) ) {
argv + + ;
argc - - ;
}
2016-08-04 14:42:57 +03:00
if ( ! argc ) {
_discard_log_report_content ( cmd ) ;
2007-02-14 19:51:48 +03:00
continue ;
2016-08-04 14:42:57 +03:00
}
2007-02-14 19:51:48 +03:00
2016-07-25 13:20:22 +03:00
log_set_report_object_name_and_id ( argv [ 0 ] , NULL ) ;
2016-08-04 14:42:57 +03:00
is_lastlog_cmd = ! strcmp ( argv [ 0 ] , " lastlog " ) ;
if ( ! is_lastlog_cmd )
_discard_log_report_content ( cmd ) ;
2007-02-14 19:51:48 +03:00
if ( ! strcmp ( argv [ 0 ] , " quit " ) | | ! strcmp ( argv [ 0 ] , " exit " ) ) {
2016-08-04 14:42:57 +03:00
_discard_log_report_content ( cmd ) ;
2007-02-14 19:51:48 +03:00
remove_history ( history_length - 1 ) ;
log_error ( " Exiting. " ) ;
break ;
}
ret = lvm_run_command ( cmd , argc , argv ) ;
if ( ret = = ENO_SUCH_CMD )
log_error ( " No such command '%s'. Try 'help'. " ,
argv [ 0 ] ) ;
2008-06-06 23:28:35 +04:00
if ( ( ret ! = ECMD_PROCESSED ) & & ! error_message_produced ( ) ) {
2009-12-16 22:22:11 +03:00
log_debug ( INTERNAL_ERROR " Failed command did not use log_error " ) ;
2008-06-06 23:28:35 +04:00
log_error ( " Command failed with status code %d. " , ret ) ;
}
2007-02-14 19:51:48 +03:00
_write_history ( ) ;
2016-07-25 13:20:22 +03:00
if ( ! is_lastlog_cmd )
_log_shell_command_status ( cmd , ret ) ;
2016-08-04 14:42:57 +03:00
log_set_report ( NULL ) ;
dm_report_group_output_and_pop_all ( cmd - > cmd_report . report_group ) ;
if ( cmd - > cmd_report . log_rh & &
! ( dm_report_group_push ( cmd - > cmd_report . report_group ,
cmd - > cmd_report . log_rh ,
( void * ) cmd - > cmd_report . log_name ) ) ) {
log_set_report ( NULL ) ;
log_error ( " Failed to add log report. " ) ;
break ;
}
2007-02-14 19:51:48 +03:00
}
2016-07-25 13:20:22 +03:00
log_restore_report_state ( saved_log_report_state ) ;
2016-05-20 15:23:43 +03:00
cmd - > is_interactive = 0 ;
2007-02-14 19:51:48 +03:00
free ( input ) ;
2016-08-04 14:42:57 +03:00
if ( cmd - > cmd_report . report_group ) {
dm_report_group_destroy ( cmd - > cmd_report . report_group ) ;
cmd - > cmd_report . report_group = NULL ;
}
if ( cmd - > cmd_report . log_rh ) {
dm_report_free ( cmd - > cmd_report . log_rh ) ;
cmd - > cmd_report . report_group = NULL ;
}
2007-02-14 19:51:48 +03:00
return 0 ;
}
# endif /* READLINE_SUPPORT */