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 )
{
2021-09-24 23:08:26 +03:00
/* coverity[os_cmd_sink] intentionally passing 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
2020-09-26 22:32:55 +03:00
# if defined(READLINE_SUPPORT) || defined(EDITLINE_SUPPORT)
# 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)
# define rl_completion_func_t CPPFunction
# endif
# elif defined(EDITLINE_SUPPORT)
# include <editline / readline.h>
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 ) ;
}
2024-05-12 13:04:54 +03:00
for ( ; i < _cmdline - > num_command_names ; + + i )
if ( ! strncmp ( text , _cmdline - > command_names [ i ] . name , len ) )
2024-05-24 20:49:08 +03:00
/* increase position for next iteration */
return strdup ( _cmdline - > command_names [ i + + ] . name ) ;
2007-02-14 19:51:48 +03:00
return NULL ;
}
/* List matching arguments */
static char * _list_args ( const char * text , int state )
{
static int match_no = 0 ;
static size_t len = 0 ;
2024-05-12 13:04:54 +03:00
static const struct command_name * cname ;
static const struct command_name_args * cna ;
2007-02-14 19:51:48 +03:00
/* 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 ;
commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. Generate help text and man pages from them.
The new file command-lines.in defines a prototype for every
unique lvm command. A unique lvm command is a unique
combination of: command name + required option args +
required positional args. Each of these prototypes also
includes the optional option args and optional positional
args that the command will accept, a description, and a
unique string ID for the definition. Any valid command
will match one of the prototypes.
Here's an example of the lvresize command definitions from
command-lines.in, there are three unique lvresize commands:
lvresize --size SizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.
lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
FLAGS: SECONDARY_SYNTAX
lvresize --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize a pool metadata SubLV by a specified size.
The three commands have separate definitions because they have
different required parameters. Required parameters are specified
on the first line of the definition. Optional options are
listed after OO, and optional positional args are listed after OP.
This data is used to generate corresponding command definition
structures for lvm in command-lines.h. usage/help output is also
auto generated, so it is always in sync with the definitions.
Every user-entered command is compared against the set of
command structures, and matched with one. An error is
reported if an entered command does not have the required
parameters for any definition. The closest match is printed
as a suggestion, and running lvresize --help will display
the usage for each possible lvresize command.
The prototype syntax used for help/man output includes
required --option and positional args on the first line,
and optional --option and positional args enclosed in [ ]
on subsequent lines.
command_name <required_opt_args> <required_pos_args>
[ <optional_opt_args> ]
[ <optional_pos_args> ]
Command definitions that are not to be advertised/suggested
have the flag SECONDARY_SYNTAX. These commands will not be
printed in the normal help output.
Man page prototypes are also generated from the same original
command definitions, and are always in sync with the code
and help text.
Very early in command execution, a matching command definition
is found. lvm then knows the operation being done, and that
the provided args conform to the definition. This will allow
lots of ad hoc checking/validation to be removed throughout
the code.
Each command definition can also be routed to a specific
function to implement it. The function is associated with
an enum value for the command definition (generated from
the ID string.) These per-command-definition implementation
functions have not yet been created, so all commands
currently fall back to the existing per-command-name
implementation functions.
Using per-command-definition functions will allow lots of
code to be removed which tries to figure out what the
command is meant to do. This is currently based on ad hoc
and complicated option analysis. When using the new
functions, what the command is doing is already known
from the associated command definition.
2016-08-12 23:52:18 +03:00
cname = NULL ;
2024-05-12 02:14:14 +03:00
cna = NULL ;
2007-02-14 19:51:48 +03:00
len = strlen ( text ) ;
/* Find start of first word in line buffer */
while ( isspace ( * s ) )
s + + ;
commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. Generate help text and man pages from them.
The new file command-lines.in defines a prototype for every
unique lvm command. A unique lvm command is a unique
combination of: command name + required option args +
required positional args. Each of these prototypes also
includes the optional option args and optional positional
args that the command will accept, a description, and a
unique string ID for the definition. Any valid command
will match one of the prototypes.
Here's an example of the lvresize command definitions from
command-lines.in, there are three unique lvresize commands:
lvresize --size SizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.
lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
FLAGS: SECONDARY_SYNTAX
lvresize --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize a pool metadata SubLV by a specified size.
The three commands have separate definitions because they have
different required parameters. Required parameters are specified
on the first line of the definition. Optional options are
listed after OO, and optional positional args are listed after OP.
This data is used to generate corresponding command definition
structures for lvm in command-lines.h. usage/help output is also
auto generated, so it is always in sync with the definitions.
Every user-entered command is compared against the set of
command structures, and matched with one. An error is
reported if an entered command does not have the required
parameters for any definition. The closest match is printed
as a suggestion, and running lvresize --help will display
the usage for each possible lvresize command.
The prototype syntax used for help/man output includes
required --option and positional args on the first line,
and optional --option and positional args enclosed in [ ]
on subsequent lines.
command_name <required_opt_args> <required_pos_args>
[ <optional_opt_args> ]
[ <optional_pos_args> ]
Command definitions that are not to be advertised/suggested
have the flag SECONDARY_SYNTAX. These commands will not be
printed in the normal help output.
Man page prototypes are also generated from the same original
command definitions, and are always in sync with the code
and help text.
Very early in command execution, a matching command definition
is found. lvm then knows the operation being done, and that
the provided args conform to the definition. This will allow
lots of ad hoc checking/validation to be removed throughout
the code.
Each command definition can also be routed to a specific
function to implement it. The function is associated with
an enum value for the command definition (generated from
the ID string.) These per-command-definition implementation
functions have not yet been created, so all commands
currently fall back to the existing per-command-name
implementation functions.
Using per-command-definition functions will allow lots of
code to be removed which tries to figure out what the
command is meant to do. This is currently based on ad hoc
and complicated option analysis. When using the new
functions, what the command is doing is already known
from the associated command definition.
2016-08-12 23:52:18 +03:00
/* Look for word in list of command names */
for ( j = 0 ; j < _cmdline - > num_command_names ; j + + ) {
2007-02-14 19:51:48 +03:00
const char * p ;
char * q = s ;
commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. Generate help text and man pages from them.
The new file command-lines.in defines a prototype for every
unique lvm command. A unique lvm command is a unique
combination of: command name + required option args +
required positional args. Each of these prototypes also
includes the optional option args and optional positional
args that the command will accept, a description, and a
unique string ID for the definition. Any valid command
will match one of the prototypes.
Here's an example of the lvresize command definitions from
command-lines.in, there are three unique lvresize commands:
lvresize --size SizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.
lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
FLAGS: SECONDARY_SYNTAX
lvresize --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize a pool metadata SubLV by a specified size.
The three commands have separate definitions because they have
different required parameters. Required parameters are specified
on the first line of the definition. Optional options are
listed after OO, and optional positional args are listed after OP.
This data is used to generate corresponding command definition
structures for lvm in command-lines.h. usage/help output is also
auto generated, so it is always in sync with the definitions.
Every user-entered command is compared against the set of
command structures, and matched with one. An error is
reported if an entered command does not have the required
parameters for any definition. The closest match is printed
as a suggestion, and running lvresize --help will display
the usage for each possible lvresize command.
The prototype syntax used for help/man output includes
required --option and positional args on the first line,
and optional --option and positional args enclosed in [ ]
on subsequent lines.
command_name <required_opt_args> <required_pos_args>
[ <optional_opt_args> ]
[ <optional_pos_args> ]
Command definitions that are not to be advertised/suggested
have the flag SECONDARY_SYNTAX. These commands will not be
printed in the normal help output.
Man page prototypes are also generated from the same original
command definitions, and are always in sync with the code
and help text.
Very early in command execution, a matching command definition
is found. lvm then knows the operation being done, and that
the provided args conform to the definition. This will allow
lots of ad hoc checking/validation to be removed throughout
the code.
Each command definition can also be routed to a specific
function to implement it. The function is associated with
an enum value for the command definition (generated from
the ID string.) These per-command-definition implementation
functions have not yet been created, so all commands
currently fall back to the existing per-command-name
implementation functions.
Using per-command-definition functions will allow lots of
code to be removed which tries to figure out what the
command is meant to do. This is currently based on ad hoc
and complicated option analysis. When using the new
functions, what the command is doing is already known
from the associated command definition.
2016-08-12 23:52:18 +03:00
p = _cmdline - > command_names [ j ] . name ;
2007-02-14 19:51:48 +03:00
while ( * p = = * q ) {
p + + ;
q + + ;
}
if ( ( ! * p ) & & * q = = ' ' ) {
commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. Generate help text and man pages from them.
The new file command-lines.in defines a prototype for every
unique lvm command. A unique lvm command is a unique
combination of: command name + required option args +
required positional args. Each of these prototypes also
includes the optional option args and optional positional
args that the command will accept, a description, and a
unique string ID for the definition. Any valid command
will match one of the prototypes.
Here's an example of the lvresize command definitions from
command-lines.in, there are three unique lvresize commands:
lvresize --size SizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.
lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
FLAGS: SECONDARY_SYNTAX
lvresize --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize a pool metadata SubLV by a specified size.
The three commands have separate definitions because they have
different required parameters. Required parameters are specified
on the first line of the definition. Optional options are
listed after OO, and optional positional args are listed after OP.
This data is used to generate corresponding command definition
structures for lvm in command-lines.h. usage/help output is also
auto generated, so it is always in sync with the definitions.
Every user-entered command is compared against the set of
command structures, and matched with one. An error is
reported if an entered command does not have the required
parameters for any definition. The closest match is printed
as a suggestion, and running lvresize --help will display
the usage for each possible lvresize command.
The prototype syntax used for help/man output includes
required --option and positional args on the first line,
and optional --option and positional args enclosed in [ ]
on subsequent lines.
command_name <required_opt_args> <required_pos_args>
[ <optional_opt_args> ]
[ <optional_pos_args> ]
Command definitions that are not to be advertised/suggested
have the flag SECONDARY_SYNTAX. These commands will not be
printed in the normal help output.
Man page prototypes are also generated from the same original
command definitions, and are always in sync with the code
and help text.
Very early in command execution, a matching command definition
is found. lvm then knows the operation being done, and that
the provided args conform to the definition. This will allow
lots of ad hoc checking/validation to be removed throughout
the code.
Each command definition can also be routed to a specific
function to implement it. The function is associated with
an enum value for the command definition (generated from
the ID string.) These per-command-definition implementation
functions have not yet been created, so all commands
currently fall back to the existing per-command-name
implementation functions.
Using per-command-definition functions will allow lots of
code to be removed which tries to figure out what the
command is meant to do. This is currently based on ad hoc
and complicated option analysis. When using the new
functions, what the command is doing is already known
from the associated command definition.
2016-08-12 23:52:18 +03:00
cname = _cmdline - > command_names + j ;
2024-05-12 02:14:14 +03:00
cna = _cmdline - > command_names_args + j ;
2007-02-14 19:51:48 +03:00
break ;
}
}
}
commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. Generate help text and man pages from them.
The new file command-lines.in defines a prototype for every
unique lvm command. A unique lvm command is a unique
combination of: command name + required option args +
required positional args. Each of these prototypes also
includes the optional option args and optional positional
args that the command will accept, a description, and a
unique string ID for the definition. Any valid command
will match one of the prototypes.
Here's an example of the lvresize command definitions from
command-lines.in, there are three unique lvresize commands:
lvresize --size SizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.
lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
FLAGS: SECONDARY_SYNTAX
lvresize --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize a pool metadata SubLV by a specified size.
The three commands have separate definitions because they have
different required parameters. Required parameters are specified
on the first line of the definition. Optional options are
listed after OO, and optional positional args are listed after OP.
This data is used to generate corresponding command definition
structures for lvm in command-lines.h. usage/help output is also
auto generated, so it is always in sync with the definitions.
Every user-entered command is compared against the set of
command structures, and matched with one. An error is
reported if an entered command does not have the required
parameters for any definition. The closest match is printed
as a suggestion, and running lvresize --help will display
the usage for each possible lvresize command.
The prototype syntax used for help/man output includes
required --option and positional args on the first line,
and optional --option and positional args enclosed in [ ]
on subsequent lines.
command_name <required_opt_args> <required_pos_args>
[ <optional_opt_args> ]
[ <optional_pos_args> ]
Command definitions that are not to be advertised/suggested
have the flag SECONDARY_SYNTAX. These commands will not be
printed in the normal help output.
Man page prototypes are also generated from the same original
command definitions, and are always in sync with the code
and help text.
Very early in command execution, a matching command definition
is found. lvm then knows the operation being done, and that
the provided args conform to the definition. This will allow
lots of ad hoc checking/validation to be removed throughout
the code.
Each command definition can also be routed to a specific
function to implement it. The function is associated with
an enum value for the command definition (generated from
the ID string.) These per-command-definition implementation
functions have not yet been created, so all commands
currently fall back to the existing per-command-name
implementation functions.
Using per-command-definition functions will allow lots of
code to be removed which tries to figure out what the
command is meant to do. This is currently based on ad hoc
and complicated option analysis. When using the new
functions, what the command is doing is already known
from the associated command definition.
2016-08-12 23:52:18 +03:00
if ( ! cname )
2010-10-25 16:57:00 +04:00
return NULL ;
2007-02-14 19:51:48 +03:00
/* Short form arguments */
2013-04-13 05:26:37 +04:00
if ( len < 3 ) {
2024-05-24 20:49:08 +03:00
while ( match_no < cna - > num_args ) {
2013-04-13 05:26:37 +04:00
char s [ 3 ] ;
2024-05-24 20:49:08 +03:00
/* increase position for next iteration */
char c = _cmdline - > opt_names [ cna - > valid_args [ match_no + + ] ] . short_opt ;
2024-05-12 13:04:54 +03:00
if ( c ) {
sprintf ( s , " -%c " , c ) ;
if ( ! strncmp ( text , s , len ) )
return strdup ( s ) ;
}
2013-04-13 05:26:37 +04:00
}
2007-02-14 19:51:48 +03:00
}
/* Long form arguments */
2024-05-12 02:14:14 +03:00
if ( match_no < cna - > num_args )
match_no = cna - > num_args ;
2007-02-14 19:51:48 +03:00
2024-05-24 20:49:08 +03:00
while ( ( match_no - cna - > num_args ) < cna - > num_args ) {
/* increase position for next iteration */
const char * l = _cmdline - > opt_names [ cna - > valid_args [ match_no + + - cna - > num_args ] ] . long_opt ;
2007-02-14 19:51:48 +03:00
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 " ) ;
2023-10-16 13:57:41 +03:00
if ( dm_snprintf ( buffer , size , " %s%s.lvm_history " , e ? : " " , e ? " / " : " " ) < 0 ) {
2007-02-14 19:51:48 +03:00
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 ;
2017-01-13 21:02:06 +03:00
int is_lastlog_cmd = 0 , argc , ret , i ;
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 ) ;
2022-08-22 14:59:08 +03:00
log_set_report_object_type ( LOG_REPORT_OBJECT_TYPE_PRE_CMD ) ;
2016-07-25 13:20:22 +03:00
2007-02-14 19:51:48 +03:00
while ( 1 ) {
shell: also output error message about max number of args hit with JSON format
If using JSON format for lvm shell's output, the error message about
exceeding the maximum number of arguments was not reported on output if
this condition was ever hit.
This is because the JSON format (as well as any other future format)
requires extra formatting compared to "basic" format and so it also
requires extra calls when it comes to reporting. The report needs to
be added to a report group and then popped and put on output with
specialized "dm_report_group_output_and_pop_all".
This "output and pop" is normally executed after we execute the command
in the lvm shell. When we didn't get to the command exection at all because
some precondition was not met (like hitting the limit for the number of
arguments for the command here), we skipped this important call and
so there was no log report output.
Right now, it's only this exact error message for which we need to call
"output and pop" directly, all the other error messages are about
initializing and setting the log report itself which we can't report
obviously.
Before this patch:
lvm> pvs 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
lvm>
With this patch applied:
lvm> pvs 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
{
"log": [
{"log_seq_num":"1", "log_type":"error", "log_context":"shell", "log_object_type":"cmd", "log_object_name":"", "log_object_id":"", "log_object_group":"", "log_object_group_id":"", "log_message":"Too many arguments, sorry.", "log_errno":"-1", "log_ret_code":"0"}
]
}
If there's any other error message in the future before we execute the
command itself, we also need to call the "output and pop" directly.
2022-08-08 16:15:32 +03:00
/*
* Note : If we need to output the log report before we get to the dm_report_group_output_and_pop_all
* at the end of this loop , like hitting a failure situation before we execute the command itself ,
* don ' t forget to directly call dm_report_group_output_and_pop_all , otherwise no log meesage will
* appear on output ( for output formats other than ' basic ' ) .
*
* Obviously , you can ' t output the ' log report ' if the error is in initializing or setting
* the report itself . In this case , we can only return an error code , but no message .
*/
2016-08-08 16:45:46 +03:00
report_reset_cmdlog_seqnum ( ) ;
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. " ) ;
}
2022-08-22 14:59:08 +03:00
log_set_report_object_type ( LOG_REPORT_OBJECT_TYPE_PRE_CMD ) ;
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
2022-08-22 14:59:08 +03:00
log_set_report_object_name_and_id ( input , NULL ) ;
2007-02-14 19:51:48 +03:00
add_history ( input ) ;
2017-01-13 21:02:06 +03:00
for ( i = 0 ; i < MAX_ARGS ; i + + )
args [ i ] = NULL ;
2007-02-14 19:51:48 +03:00
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. " ) ;
2022-08-22 14:59:08 +03:00
goto report_log ;
2007-02-14 19:51:48 +03:00
}
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
2022-08-22 14:59:08 +03:00
log_set_report_object_type ( LOG_REPORT_OBJECT_TYPE_CMD ) ;
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 ) ;
2022-08-22 14:59:08 +03:00
report_log :
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 ) {
2017-06-27 00:21:22 +03:00
if ( ! dm_report_group_destroy ( cmd - > cmd_report . report_group ) )
stack ;
2016-08-04 14:42:57 +03:00
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 ;
}
2020-09-26 22:32:55 +03:00
# endif /* READLINE_SUPPORT || EDITLINE_SUPPORT */