2001-09-25 16:49:28 +04:00
/*
2001-12-17 19:58:17 +03:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-09-25 16:49:28 +04:00
*
2001-12-17 19:58:17 +03:00
* This file is released under the GPL .
2001-09-25 16:49:28 +04:00
*/
# include "tools.h"
2002-01-07 14:12:11 +03:00
# include "archive.h"
# include "defaults.h"
2002-01-15 20:37:23 +03:00
# include "lvm1_label.h"
# include "label.h"
2002-01-17 19:39:24 +03:00
# include "version.h"
2001-09-25 16:49:28 +04:00
2002-01-08 22:17:08 +03:00
# include "stub.h"
2001-09-25 16:49:28 +04:00
# include <assert.h>
# include <getopt.h>
# include <signal.h>
# include <syslog.h>
# include <libgen.h>
# include <sys/stat.h>
2001-10-12 14:32:06 +04:00
# include <ctype.h>
2002-01-08 02:28:25 +03:00
# include <time.h>
2002-01-21 20:43:10 +03:00
# include <stdlib.h>
2001-09-25 16:49:28 +04:00
# ifdef READLINE_SUPPORT
2002-02-12 00:00:35 +03:00
# include <readline/readline.h>
# include <readline/history.h>
# ifndef HAVE_RL_COMPLETION_MATCHES
# define rl_completion_matches(a, b) completion_matches((char *)a, b)
# endif
2001-09-25 16:49:28 +04:00
# endif
2002-02-21 13:15:54 +03:00
/*
2002-02-11 23:50:53 +03:00
* Exported table of valid switches
*/
2001-09-25 16:49:28 +04:00
struct arg the_args [ ARG_COUNT + 1 ] = {
2001-12-17 19:58:17 +03:00
# define arg(a, b, c, d) {b, "--" c, d, 0, NULL},
2001-09-25 16:49:28 +04:00
# include "args.h"
2001-12-17 19:58:17 +03:00
# undef arg
2001-09-25 16:49:28 +04:00
} ;
static int _array_size ;
static int _num_commands ;
static struct command * _commands ;
2001-11-12 18:10:01 +03:00
struct cmd_context * cmd ;
2001-10-08 22:44:22 +04:00
2001-10-24 21:53:50 +04:00
/* Whether or not to dump persistent filter state */
2001-11-14 13:44:14 +03:00
static int _dump_filter ;
2001-09-25 16:49:28 +04:00
static int _interactive ;
static FILE * _log ;
2001-12-17 19:58:17 +03:00
2002-01-15 20:37:23 +03:00
/* lvm1 label handler */
static struct labeller * _lvm1_label ;
2002-01-07 14:12:11 +03:00
/*
* This structure only contains those options that
* can have a default and per command setting .
*/
2002-01-07 12:05:31 +03:00
struct config_info {
int debug ;
int verbose ;
int test ;
2002-01-19 00:26:37 +03:00
int syslog ;
2002-01-07 12:05:31 +03:00
int archive ; /* should we archive ? */
int backup ; /* should we backup ? */
2002-01-09 22:16:48 +03:00
mode_t umask ;
2002-01-07 12:05:31 +03:00
} ;
2001-12-17 19:58:17 +03:00
2002-01-07 12:05:31 +03:00
static struct config_info _default_settings ;
static struct config_info _current_settings ;
2001-12-17 19:58:17 +03:00
2001-12-17 15:01:09 +03:00
/*
2001-12-31 18:20:18 +03:00
* The lvm_sys_dir contains :
2001-12-17 15:01:09 +03:00
*
* o The lvm configuration ( lvm . conf )
* o The persistent filter cache ( . cache )
2002-01-07 14:12:11 +03:00
* o Volume group backups ( / backup )
* o Archive of old vg configurations ( / archive )
2001-12-17 15:01:09 +03:00
*/
2001-12-31 18:20:18 +03:00
static char _sys_dir [ PATH_MAX ] = " /etc/lvm " ;
static char _dev_dir [ PATH_MAX ] ;
2002-01-16 02:34:13 +03:00
static char _proc_dir [ PATH_MAX ] ;
2001-12-31 18:20:18 +03:00
2001-09-25 16:49:28 +04:00
/* static functions */
static void register_commands ( void ) ;
static struct command * find_command ( const char * name ) ;
static void register_command ( const char * name , command_fn fn ,
const char * desc , const char * usage , . . . ) ;
static void create_new_command ( const char * name , command_fn command ,
const char * desc , const char * usage ,
int nargs , int * args ) ;
static void alloc_command ( void ) ;
static void add_getopt_arg ( int arg , char * * ptr , struct option * * o ) ;
static int process_command_line ( struct command * com , int * argc , char * * * argv ) ;
static struct arg * find_arg ( struct command * com , int a ) ;
static int process_common_commands ( struct command * com ) ;
static int run_command ( int argc , char * * argv ) ;
static int init ( void ) ;
static void fin ( void ) ;
static int run_script ( int argc , char * * argv ) ;
# ifdef READLINE_SUPPORT
static int shell ( void ) ;
# endif
static void display_help ( void ) ;
int main ( int argc , char * * argv )
{
char * namebase , * base ;
int ret , alias = 0 ;
if ( ! init ( ) )
return - 1 ;
namebase = strdup ( argv [ 0 ] ) ;
base = basename ( namebase ) ;
2002-01-29 20:23:33 +03:00
while ( * base = = ' / ' )
base + + ;
2001-09-25 16:49:28 +04:00
if ( strcmp ( base , " lvm " ) )
alias = 1 ;
free ( namebase ) ;
register_commands ( ) ;
# ifdef READLINE_SUPPORT
if ( ! alias & & argc = = 1 ) {
ret = shell ( ) ;
goto out ;
}
# endif
if ( ! alias ) {
if ( argc < 2 ) {
log_fatal ( " Please supply an LVM command. " ) ;
display_help ( ) ;
2001-10-06 01:39:30 +04:00
ret = EINVALID_CMD_LINE ;
2001-09-25 16:49:28 +04:00
goto out ;
}
argc - - ;
argv + + ;
}
ret = run_command ( argc , argv ) ;
2001-10-06 01:39:30 +04:00
if ( ( ret = = ENO_SUCH_CMD ) & & ( ! alias ) )
2001-09-25 16:49:28 +04:00
ret = run_script ( argc , argv ) ;
2001-10-06 01:39:30 +04:00
if ( ret = = ENO_SUCH_CMD )
2001-10-15 16:49:58 +04:00
log_error ( " No such command. Try 'help'. " ) ;
2001-09-25 16:49:28 +04:00
out :
fin ( ) ;
return ret ;
}
void usage ( const char * name )
{
struct command * com = find_command ( name ) ;
if ( ! com )
return ;
log_error ( " %s: %s \n \n %s " , com - > name , com - > desc , com - > usage ) ;
}
int yes_no_arg ( struct arg * a )
{
2001-11-10 01:01:04 +03:00
a - > sign = SIGN_NONE ;
2001-09-25 16:49:28 +04:00
if ( ! strcmp ( a - > value , " y " ) )
a - > i_value = 1 ;
else if ( ! strcmp ( a - > value , " n " ) )
a - > i_value = 0 ;
else
return 0 ;
return 1 ;
}
2001-11-10 01:01:04 +03:00
int _get_int_arg ( struct arg * a , char * * ptr )
2001-09-25 16:49:28 +04:00
{
2001-11-10 01:01:04 +03:00
char * val ;
long v ;
val = a - > value ;
switch ( * val ) {
case ' + ' :
a - > sign = SIGN_PLUS ;
val + + ;
break ;
case ' - ' :
a - > sign = SIGN_MINUS ;
val + + ;
break ;
default :
a - > sign = SIGN_NONE ;
}
if ( ! isdigit ( * val ) )
return 0 ;
v = strtol ( val , ptr , 10 ) ;
2001-09-25 16:49:28 +04:00
2001-11-10 01:01:04 +03:00
if ( * ptr = = val )
return 0 ;
a - > i_value = ( uint32_t ) v ;
return 1 ;
}
int size_arg ( struct arg * a )
{
2001-09-25 16:49:28 +04:00
char * ptr ;
int i ;
2001-11-10 01:01:04 +03:00
static char * suffixes = " kmgt " ;
2002-01-21 20:43:10 +03:00
char * val ;
double v ;
val = a - > value ;
switch ( * val ) {
case ' + ' :
a - > sign = SIGN_PLUS ;
val + + ;
break ;
case ' - ' :
a - > sign = SIGN_MINUS ;
val + + ;
break ;
default :
a - > sign = SIGN_NONE ;
}
2001-09-25 16:49:28 +04:00
2002-01-21 20:43:10 +03:00
if ( ! isdigit ( * val ) )
return 0 ;
v = strtod ( val , & ptr ) ;
if ( ptr = = val )
2001-09-25 16:49:28 +04:00
return 0 ;
if ( * ptr ) {
for ( i = strlen ( suffixes ) - 1 ; i > = 0 ; i - - )
if ( suffixes [ i ] = = tolower ( ( int ) * ptr ) )
break ;
if ( i < 0 )
return 0 ;
while ( i - - > 0 )
2002-01-21 20:43:10 +03:00
v * = 1024 ;
2001-09-25 16:49:28 +04:00
}
2002-01-21 20:43:10 +03:00
a - > i_value = ( uint32_t ) v ;
2002-02-15 17:33:59 +03:00
a - > i64_value = ( uint64_t ) v ;
2001-09-25 16:49:28 +04:00
return 1 ;
}
int int_arg ( struct arg * a )
{
char * ptr ;
2001-11-10 01:01:04 +03:00
if ( ! _get_int_arg ( a , & ptr ) | | ( * ptr ) | | ( a - > sign = = SIGN_MINUS ) )
return 0 ;
return 1 ;
}
int int_arg_with_sign ( struct arg * a )
{
char * ptr ;
if ( ! _get_int_arg ( a , & ptr ) | | ( * ptr ) )
2001-09-25 16:49:28 +04:00
return 0 ;
return 1 ;
}
2002-02-01 20:54:39 +03:00
int minor_arg ( struct arg * a )
{
char * ptr ;
if ( ! _get_int_arg ( a , & ptr ) | | ( * ptr ) | | ( a - > sign = = SIGN_MINUS ) )
return 0 ;
if ( a - > i_value > 255 ) {
log_error ( " Minor number outside range 0-255 " ) ;
return 0 ;
}
return 1 ;
}
2001-09-25 16:49:28 +04:00
int string_arg ( struct arg * a )
{
return 1 ;
}
int permission_arg ( struct arg * a )
{
2001-11-10 01:01:04 +03:00
a - > sign = SIGN_NONE ;
2001-09-25 16:49:28 +04:00
if ( ( ! strcmp ( a - > value , " rw " ) ) | | ( ! strcmp ( a - > value , " wr " ) ) )
2001-10-06 01:39:30 +04:00
a - > i_value = LVM_READ | LVM_WRITE ;
2001-09-25 16:49:28 +04:00
else if ( ! strcmp ( a - > value , " r " ) )
2001-10-06 01:39:30 +04:00
a - > i_value = LVM_READ ;
2001-09-25 16:49:28 +04:00
else
return 0 ;
return 1 ;
}
2001-10-12 14:32:06 +04:00
char yes_no_prompt ( const char * prompt , . . . )
2001-09-25 16:49:28 +04:00
{
int c = 0 ;
va_list ap ;
while ( c ! = ' y ' & & c ! = ' n ' ) {
if ( c = = ' \n ' | | c = = 0 ) {
va_start ( ap , prompt ) ;
vprintf ( prompt , ap ) ;
va_end ( ap ) ;
}
c = tolower ( getchar ( ) ) ;
}
2001-10-12 14:32:06 +04:00
2001-11-10 01:01:04 +03:00
while ( getchar ( ) ! = ' \n ' ) ;
2001-10-12 14:32:06 +04:00
2001-09-25 16:49:28 +04:00
return c ;
}
static void register_commands ( )
{
# define xx(a, b, c...) register_command(# a, a, b, ## c, \
2002-02-18 18:52:48 +03:00
debug_ARG , help_ARG , \
2001-12-17 19:58:17 +03:00
version_ARG , verbose_ARG , \
quiet_ARG , - 1 ) ;
2001-09-25 16:49:28 +04:00
# include "commands.h"
# undef xx
}
static void register_command ( const char * name , command_fn fn ,
const char * desc , const char * usage , . . . )
{
int nargs = 0 , i ;
int * args ;
va_list ap ;
/* count how many arguments we have */
va_start ( ap , usage ) ;
while ( va_arg ( ap , int ) > = 0 )
nargs + + ;
va_end ( ap ) ;
/* allocate space for them */
2001-11-10 01:01:04 +03:00
if ( ! ( args = dbg_malloc ( sizeof ( * args ) * nargs ) ) ) {
2001-09-25 16:49:28 +04:00
log_fatal ( " Out of memory. " ) ;
2001-10-06 01:39:30 +04:00
exit ( ECMD_FAILED ) ;
2001-09-25 16:49:28 +04:00
}
/* fill them in */
va_start ( ap , usage ) ;
for ( i = 0 ; i < nargs ; i + + )
args [ i ] = va_arg ( ap , int ) ;
va_end ( ap ) ;
/* enter the command in the register */
create_new_command ( name , fn , desc , usage , nargs , args ) ;
}
static struct command * find_command ( const char * name )
{
int i ;
char * namebase , * base ;
namebase = strdup ( name ) ;
base = basename ( namebase ) ;
for ( i = 0 ; i < _num_commands ; i + + ) {
if ( ! strcmp ( base , _commands [ i ] . name ) )
break ;
}
free ( namebase ) ;
if ( i > = _num_commands )
return 0 ;
return _commands + i ;
}
static void create_new_command ( const char * name , command_fn command ,
const char * desc , const char * usage ,
int nargs , int * args )
{
struct command * nc ;
alloc_command ( ) ;
nc = _commands + _num_commands + + ;
nc - > name = name ;
nc - > desc = desc ;
nc - > usage = usage ;
nc - > fn = command ;
nc - > num_args = nargs ;
nc - > valid_args = args ;
}
static void __alloc ( int size )
{
2001-11-10 01:01:04 +03:00
if ( ! ( _commands = dbg_realloc ( _commands , sizeof ( * _commands ) * size ) ) ) {
2001-09-25 16:49:28 +04:00
log_fatal ( " Couldn't allocate memory. " ) ;
2001-10-06 01:39:30 +04:00
exit ( ECMD_FAILED ) ;
2001-09-25 16:49:28 +04:00
}
_array_size = size ;
}
static void alloc_command ( void )
{
if ( ! _array_size )
__alloc ( 32 ) ;
if ( _array_size < = _num_commands )
__alloc ( 2 * _array_size ) ;
}
2001-12-17 13:08:27 +03:00
/*
* Sets up the short and long argument . If there
* is no short argument then the index of the
* argument in the the_args array is set as the
* long opt value . Yuck . Of course this means we
* can ' t have more than ' a ' long arguments . Since
* we have only 1 ATM ( - - version ) I think we can
* live with this restriction .
*/
2001-09-25 16:49:28 +04:00
static void add_getopt_arg ( int arg , char * * ptr , struct option * * o )
{
struct arg * a = the_args + arg ;
if ( a - > short_arg ) {
* ( * ptr ) + + = a - > short_arg ;
if ( a - > fn )
* ( * ptr ) + + = ' : ' ;
}
if ( * ( a - > long_arg + 2 ) ) {
( * o ) - > name = a - > long_arg + 2 ;
( * o ) - > has_arg = a - > fn ? 1 : 0 ;
( * o ) - > flag = NULL ;
2001-12-17 13:08:27 +03:00
( * o ) - > val = arg ;
2001-09-25 16:49:28 +04:00
( * o ) + + ;
}
}
static int process_command_line ( struct command * com , int * argc , char * * * argv )
{
int i , opt ;
char str [ ( ( ARG_COUNT + 1 ) * 2 ) + 1 ] , * ptr = str ;
struct option opts [ ARG_COUNT + 1 ] , * o = opts ;
struct arg * a ;
for ( i = 0 ; i < ARG_COUNT ; i + + ) {
struct arg * a = the_args + i ;
/* zero the count and arg */
a - > count = 0 ;
a - > value = 0 ;
a - > i_value = 0 ;
}
/* fill in the short and long opts */
for ( i = 0 ; i < com - > num_args ; i + + )
add_getopt_arg ( com - > valid_args [ i ] , & ptr , & o ) ;
* ptr = ' \0 ' ;
2001-11-10 01:01:04 +03:00
memset ( o , 0 , sizeof ( * o ) ) ;
2001-09-25 16:49:28 +04:00
/* initialise getopt_long & scan for command line switches */
optarg = 0 ;
optind = 0 ;
while ( ( opt = getopt_long ( * argc , * argv , str , opts , NULL ) ) > = 0 ) {
a = find_arg ( com , opt ) ;
if ( ! a ) {
log_fatal ( " Unrecognised option. " ) ;
return 0 ;
}
if ( a - > fn ) {
2001-12-17 19:58:17 +03:00
2001-09-25 16:49:28 +04:00
if ( ! optarg ) {
log_error ( " Option requires argument. " ) ;
return 0 ;
}
a - > value = optarg ;
if ( ! a - > fn ( a ) ) {
2001-12-31 18:20:18 +03:00
log_error ( " Invalid argument %s " , optarg ) ;
2001-09-25 16:49:28 +04:00
return 0 ;
}
}
a - > count + + ;
}
* argc - = optind ;
* argv + = optind ;
return 1 ;
}
static struct arg * find_arg ( struct command * com , int opt )
{
struct arg * a ;
2001-12-17 13:08:27 +03:00
int i , arg ;
2001-09-25 16:49:28 +04:00
for ( i = 0 ; i < com - > num_args ; i + + ) {
2001-12-17 13:08:27 +03:00
arg = com - > valid_args [ i ] ;
a = the_args + arg ;
/*
* opt should equal either the
* short arg , or the index into
* ' the_args ' .
*/
if ( ( a - > short_arg & & ( opt = = a - > short_arg ) ) | | ( opt = = arg ) )
2001-09-25 16:49:28 +04:00
return a ;
}
return 0 ;
}
2002-01-10 17:46:50 +03:00
static int merge_synonym ( int oldarg , int newarg )
2001-09-25 16:49:28 +04:00
{
2002-01-10 17:46:50 +03:00
struct arg * old , * new ;
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , oldarg ) & & arg_count ( cmd , newarg ) ) {
2002-01-10 17:46:50 +03:00
log_error ( " %s and %s are synonyms. Please only supply one. " ,
2002-02-12 00:00:35 +03:00
the_args [ oldarg ] . long_arg , the_args [ newarg ] . long_arg ) ;
2002-01-10 17:46:50 +03:00
return 0 ;
}
2001-09-25 16:49:28 +04:00
2002-02-12 00:00:35 +03:00
if ( ! arg_count ( cmd , oldarg ) )
2002-01-10 17:46:50 +03:00
return 1 ;
old = the_args + oldarg ;
new = the_args + newarg ;
new - > count = old - > count ;
new - > value = old - > value ;
new - > i_value = old - > i_value ;
new - > sign = old - > sign ;
return 1 ;
}
2002-02-11 23:50:53 +03:00
int version ( struct cmd_context * cmd , int argc , char * * argv )
2002-01-17 19:39:24 +03:00
{
char version [ 80 ] ;
log_error ( " LVM version: %s " , LVM_VERSION ) ;
if ( library_version ( version , sizeof ( version ) ) )
log_error ( " Library version: %s " , version ) ;
if ( driver_version ( version , sizeof ( version ) ) )
log_error ( " Driver version: %s " , version ) ;
return ECMD_PROCESSED ;
}
2002-01-10 17:46:50 +03:00
static int process_common_commands ( struct command * com )
{
2002-01-07 12:05:31 +03:00
_current_settings = _default_settings ;
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , debug_ARG ) )
2002-01-15 20:37:23 +03:00
_current_settings . debug = _LOG_FATAL +
2002-02-12 00:00:35 +03:00
( arg_count ( cmd , debug_ARG ) - 1 ) ;
2001-12-17 19:58:17 +03:00
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , verbose_ARG ) )
_current_settings . verbose = arg_count ( cmd , verbose_ARG ) ;
2001-12-17 19:58:17 +03:00
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , quiet_ARG ) ) {
2002-01-07 12:05:31 +03:00
_current_settings . debug = 0 ;
_current_settings . verbose = 0 ;
2001-12-17 19:58:17 +03:00
}
2001-09-25 16:49:28 +04:00
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , test_ARG ) )
_current_settings . test = arg_count ( cmd , test_ARG ) ;
2001-09-25 16:49:28 +04:00
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , help_ARG ) ) {
2001-09-25 16:49:28 +04:00
usage ( com - > name ) ;
2001-10-06 01:39:30 +04:00
return ECMD_PROCESSED ;
2001-09-25 16:49:28 +04:00
}
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , version_ARG ) ) {
return version ( cmd , 0 , ( char * * ) NULL ) ;
2001-09-25 16:49:28 +04:00
}
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , autobackup_ARG ) ) {
2002-01-10 17:46:50 +03:00
_current_settings . archive = 1 ;
_current_settings . backup = 1 ;
}
2002-02-12 00:00:35 +03:00
if ( arg_count ( cmd , partial_ARG ) ) {
2002-01-29 20:23:33 +03:00
init_partial ( 1 ) ;
2002-01-29 22:19:37 +03:00
log_print ( " Partial mode. Incomplete volume groups will "
" be activated read-only. " ) ;
2002-02-12 00:00:35 +03:00
} else
2002-01-29 20:23:33 +03:00
init_partial ( 0 ) ;
2002-01-10 17:46:50 +03:00
/* Handle synonyms */
if ( ! merge_synonym ( resizable_ARG , resizeable_ARG ) | |
! merge_synonym ( allocation_ARG , allocatable_ARG ) | |
! merge_synonym ( allocation_ARG , resizeable_ARG ) )
return ECMD_FAILED ;
2001-09-25 16:49:28 +04:00
2001-12-31 18:20:18 +03:00
/* Zero indicates it's OK to continue processing this command */
2001-09-25 16:49:28 +04:00
return 0 ;
}
2002-02-11 23:50:53 +03:00
int help ( struct cmd_context * cmd , int argc , char * * argv )
2001-09-25 16:49:28 +04:00
{
if ( ! argc )
display_help ( ) ;
else {
int i ;
for ( i = 0 ; i < argc ; i + + )
usage ( argv [ i ] ) ;
}
return 0 ;
}
2001-12-17 15:01:09 +03:00
static void display_help ( void )
2001-09-25 16:49:28 +04:00
{
int i ;
log_error ( " Available lvm commands: " ) ;
log_error ( " Use 'lvm help <command>' for more information " ) ;
2001-10-08 22:44:22 +04:00
log_error ( " " ) ;
2001-09-25 16:49:28 +04:00
for ( i = 0 ; i < _num_commands ; i + + ) {
struct command * com = _commands + i ;
log_error ( " %-16.16s%s " , com - > name , com - > desc ) ;
}
}
2002-01-07 12:05:31 +03:00
static void _use_settings ( struct config_info * settings )
{
init_debug ( settings - > debug ) ;
init_verbose ( settings - > verbose ) ;
init_test ( settings - > test ) ;
archive_enable ( settings - > archive ) ;
backup_enable ( settings - > backup ) ;
}
2002-02-08 14:13:47 +03:00
static char * _copy_command_line ( struct pool * mem , int argc , char * * argv )
{
int i ;
/*
* Build up the complete command line , used as a
* description for backups .
*/
if ( ! pool_begin_object ( cmd - > mem , 128 ) )
goto bad ;
for ( i = 0 ; i < argc ; i + + ) {
if ( ! pool_grow_object ( cmd - > mem , argv [ i ] , strlen ( argv [ i ] ) ) )
goto bad ;
if ( i < ( argc - 1 ) )
2002-02-12 00:00:35 +03:00
if ( ! pool_grow_object ( cmd - > mem , " " , 1 ) ) ;
2002-02-08 14:13:47 +03:00
}
/*
* Terminate .
*/
if ( ! pool_grow_object ( mem , " \0 " , 1 ) )
2002-02-12 00:00:35 +03:00
goto bad ;
2002-02-08 14:13:47 +03:00
return pool_end_object ( mem ) ;
2002-02-12 00:00:35 +03:00
bad :
2002-02-08 14:13:47 +03:00
log_err ( " Couldn't copy command line. " ) ;
pool_abandon_object ( mem ) ;
return NULL ;
}
2001-09-25 16:49:28 +04:00
static int run_command ( int argc , char * * argv )
{
int ret = 0 ;
2002-02-11 18:42:34 +03:00
int locking_type ;
2001-09-25 16:49:28 +04:00
2002-02-08 14:13:47 +03:00
if ( ! ( cmd - > cmd_line = _copy_command_line ( cmd - > mem , argc , argv ) ) )
return ECMD_FAILED ;
2002-02-11 23:50:53 +03:00
if ( ! ( cmd - > command = find_command ( argv [ 0 ] ) ) )
2001-10-06 01:39:30 +04:00
return ENO_SUCH_CMD ;
2001-09-25 16:49:28 +04:00
2002-02-11 23:50:53 +03:00
if ( ! process_command_line ( cmd - > command , & argc , & argv ) ) {
2001-09-25 16:49:28 +04:00
log_error ( " Error during parsing of command line. " ) ;
2001-10-06 01:39:30 +04:00
return EINVALID_CMD_LINE ;
2001-09-25 16:49:28 +04:00
}
2002-02-11 23:50:53 +03:00
set_cmd_name ( cmd - > command - > name ) ;
2002-01-22 18:33:40 +03:00
2002-02-11 23:50:53 +03:00
if ( ( ret = process_common_commands ( cmd - > command ) ) )
2001-09-25 16:49:28 +04:00
return ret ;
2002-01-07 12:05:31 +03:00
_use_settings ( & _current_settings ) ;
2002-01-22 18:33:40 +03:00
2002-02-12 00:00:35 +03:00
locking_type = find_config_int ( cmd - > cf - > root , " global/locking_type " ,
2002-02-11 18:42:34 +03:00
' / ' , 1 ) ;
if ( ! init_locking ( locking_type , cmd - > cf ) ) {
log_error ( " Locking type %d initialisation failed. " ,
locking_type ) ;
return 0 ;
}
2002-02-11 23:50:53 +03:00
ret = cmd - > command - > fn ( cmd , argc , argv ) ;
2001-09-25 16:49:28 +04:00
2002-02-11 18:42:34 +03:00
fin_locking ( ) ;
2001-12-17 19:58:17 +03:00
/*
* set the debug and verbose levels back
2002-01-07 12:05:31 +03:00
* to the global default . We have to do
* this so the logging levels get set
* correctly for program exit .
2001-12-17 19:58:17 +03:00
*/
2002-01-07 12:05:31 +03:00
_use_settings ( & _default_settings ) ;
2001-12-17 19:58:17 +03:00
2001-10-12 18:25:53 +04:00
/*
* free off any memory the command used .
*/
2001-11-12 18:10:01 +03:00
pool_empty ( cmd - > mem ) ;
2001-10-12 18:25:53 +04:00
2001-10-06 01:39:30 +04:00
if ( ret = = EINVALID_CMD_LINE & & ! _interactive )
2002-02-11 23:50:53 +03:00
usage ( cmd - > command - > name ) ;
2001-09-25 16:49:28 +04:00
return ret ;
}
static int split ( char * str , int * argc , char * * argv , int max )
{
char * b = str , * e ;
* argc = 0 ;
while ( * b ) {
while ( * b & & isspace ( * b ) )
b + + ;
if ( ( ! * b ) | | ( * b = = ' # ' ) )
break ;
e = b ;
while ( * e & & ! isspace ( * e ) )
e + + ;
argv [ ( * argc ) + + ] = b ;
if ( ! * e )
break ;
* e + + = ' \0 ' ;
b = e ;
if ( * argc = = max )
break ;
}
return * argc ;
}
2002-01-07 17:21:33 +03:00
static void _init_rand ( void )
{
srand ( ( unsigned int ) time ( NULL ) + ( unsigned int ) getpid ( ) ) ;
}
2001-09-25 16:49:28 +04:00
static void __init_log ( struct config_file * cf )
{
2001-10-25 21:25:48 +04:00
char * open_mode = " a " ;
2002-01-22 18:33:40 +03:00
const char * log_file , * prefix ;
2002-01-19 00:26:37 +03:00
_default_settings . syslog =
2002-02-12 00:00:35 +03:00
find_config_int ( cf - > root , " log/syslog " , ' / ' , 1 ) ;
2002-01-19 00:26:37 +03:00
if ( _default_settings . syslog ! = 1 )
fin_syslog ( ) ;
if ( _default_settings . syslog > 1 )
init_syslog ( _default_settings . syslog ) ;
2001-09-25 16:49:28 +04:00
2002-01-09 22:16:48 +03:00
_default_settings . debug =
2002-02-12 00:00:35 +03:00
find_config_int ( cf - > root , " log/level " , ' / ' , 0 ) ;
2002-01-19 00:26:37 +03:00
init_debug ( _default_settings . debug ) ;
2002-01-09 22:16:48 +03:00
_default_settings . verbose =
2002-02-12 00:00:35 +03:00
find_config_int ( cf - > root , " log/verbose " , ' / ' , 0 ) ;
2002-01-19 00:26:37 +03:00
init_verbose ( _default_settings . verbose ) ;
2002-01-22 18:33:40 +03:00
init_indent ( find_config_int ( cf - > root , " log/indent " , ' / ' , 1 ) ) ;
if ( ( prefix = find_config_str ( cf - > root , " log/prefix " , ' / ' , 0 ) ) )
init_msg_prefix ( prefix ) ;
init_cmd_name ( find_config_int ( cf - > root , " log/command_names " , ' / ' , 0 ) ) ;
2002-02-08 14:13:47 +03:00
_default_settings . test = find_config_int ( cf - > root , " global/test " ,
2002-01-16 18:20:51 +03:00
' / ' , 0 ) ;
2001-10-25 21:25:48 +04:00
if ( find_config_int ( cf - > root , " log/overwrite " , ' / ' , 0 ) )
open_mode = " w " ;
2002-01-19 00:26:37 +03:00
log_file = find_config_str ( cf - > root , " log/file " , ' / ' , 0 ) ;
2001-09-25 16:49:28 +04:00
if ( log_file ) {
/* set up the logging */
2001-10-25 21:25:48 +04:00
if ( ! ( _log = fopen ( log_file , open_mode ) ) )
2001-10-23 15:50:49 +04:00
log_error ( " Couldn't open log file %s " , log_file ) ;
2001-09-25 16:49:28 +04:00
else
init_log ( _log ) ;
}
}
2002-01-07 14:12:11 +03:00
static int _init_backup ( struct config_file * cf )
{
int days , min ;
char default_dir [ PATH_MAX ] ;
const char * dir ;
2002-01-09 16:17:14 +03:00
if ( ! _sys_dir ) {
log_warn ( " WARNING: Metadata changes will NOT be backed up " ) ;
backup_init ( " " ) ;
archive_init ( " " , 0 , 0 ) ;
return 1 ;
}
2002-01-07 14:12:11 +03:00
/* set up archiving */
_default_settings . archive =
2002-02-12 00:00:35 +03:00
find_config_bool ( cmd - > cf - > root , " backup/archive " , ' / ' ,
DEFAULT_ARCHIVE_ENABLED ) ;
2002-01-07 14:12:11 +03:00
days = find_config_int ( cmd - > cf - > root , " backup/retain_days " , ' / ' ,
DEFAULT_ARCHIVE_DAYS ) ;
min = find_config_int ( cmd - > cf - > root , " backup/retain_min " , ' / ' ,
2002-02-12 00:00:35 +03:00
DEFAULT_ARCHIVE_NUMBER ) ;
2002-01-07 14:12:11 +03:00
if ( lvm_snprintf ( default_dir , sizeof ( default_dir ) , " %s/%s " , _sys_dir ,
DEFAULT_ARCHIVE_SUBDIR ) = = - 1 ) {
log_err ( " Couldn't create default archive path '%s/%s'. " ,
_sys_dir , DEFAULT_ARCHIVE_SUBDIR ) ;
return 0 ;
}
dir = find_config_str ( cmd - > cf - > root , " backup/archive_dir " , ' / ' ,
default_dir ) ;
if ( ! archive_init ( dir , days , min ) ) {
log_debug ( " backup_init failed. " ) ;
return 0 ;
}
/* set up the backup */
_default_settings . backup =
2002-02-12 00:00:35 +03:00
find_config_bool ( cmd - > cf - > root , " backup/backup " , ' / ' ,
DEFAULT_BACKUP_ENABLED ) ;
2002-01-07 14:12:11 +03:00
if ( lvm_snprintf ( default_dir , sizeof ( default_dir ) , " %s/%s " , _sys_dir ,
DEFAULT_BACKUP_SUBDIR ) = = - 1 ) {
log_err ( " Couldn't create default backup path '%s/%s'. " ,
_sys_dir , DEFAULT_BACKUP_SUBDIR ) ;
return 0 ;
}
dir = find_config_str ( cmd - > cf - > root , " backup/backup_dir " , ' / ' ,
default_dir ) ;
if ( ! backup_init ( dir ) ) {
log_debug ( " backup_init failed. " ) ;
return 0 ;
}
return 1 ;
}
2001-11-13 17:17:50 +03:00
static int dev_cache_setup ( struct config_file * cf )
2001-10-23 15:50:49 +04:00
{
struct config_node * cn ;
struct config_value * cv ;
if ( ! dev_cache_init ( ) ) {
stack ;
return 0 ;
}
2001-11-13 17:17:50 +03:00
if ( ! ( cn = find_config_node ( cf - > root , " devices/scan " , ' / ' ) ) ) {
2001-10-23 15:50:49 +04:00
if ( ! dev_cache_add_dir ( " /dev " ) ) {
log_error ( " Failed to add /dev to internal "
" device cache " ) ;
return 0 ;
}
2001-11-10 01:01:04 +03:00
log_verbose
( " device/scan not in config file: Defaulting to /dev " ) ;
2001-10-23 22:20:27 +04:00
return 1 ;
2001-10-23 15:50:49 +04:00
}
for ( cv = cn - > v ; cv ; cv = cv - > next ) {
if ( cv - > type ! = CFG_STRING ) {
log_error ( " Invalid string in config file: "
" devices/scan " ) ;
return 0 ;
}
2001-11-10 01:01:04 +03:00
2001-10-23 15:50:49 +04:00
if ( ! dev_cache_add_dir ( cv - > v . str ) ) {
2001-11-10 01:01:04 +03:00
log_error ( " Failed to add %s to internal device cache " ,
2001-10-23 15:50:49 +04:00
cv - > v . str ) ;
return 0 ;
}
2001-11-10 01:01:04 +03:00
}
2001-10-23 15:50:49 +04:00
return 1 ;
}
2001-11-13 17:17:50 +03:00
static struct dev_filter * filter_components_setup ( struct config_file * cf )
2001-10-23 15:50:49 +04:00
{
struct config_node * cn ;
2001-10-23 22:20:27 +04:00
struct dev_filter * f1 , * f2 , * f3 ;
2001-10-23 15:50:49 +04:00
2002-01-16 02:34:13 +03:00
if ( ! ( f2 = lvm_type_filter_create ( _proc_dir ) ) )
2001-10-23 15:50:49 +04:00
return 0 ;
2001-11-13 17:17:50 +03:00
if ( ! ( cn = find_config_node ( cf - > root , " devices/filter " , ' / ' ) ) ) {
2001-10-23 22:20:27 +04:00
log_debug ( " devices/filter not found in config file: no regex "
" filter installed " ) ;
2001-10-23 16:33:57 +04:00
return f2 ;
2001-10-23 15:50:49 +04:00
}
2001-10-23 16:33:57 +04:00
if ( ! ( f1 = regex_filter_create ( cn - > v ) ) ) {
2001-10-23 15:50:49 +04:00
log_error ( " Failed to create regex device filter " ) ;
2001-10-23 16:33:57 +04:00
return f2 ;
2001-10-23 15:50:49 +04:00
}
2001-10-23 22:20:27 +04:00
if ( ! ( f3 = composite_filter_create ( 2 , f1 , f2 ) ) ) {
2001-10-23 15:50:49 +04:00
log_error ( " Failed to create composite device filter " ) ;
2001-10-23 16:33:57 +04:00
return f2 ;
2001-10-23 15:50:49 +04:00
}
2001-10-23 22:20:27 +04:00
return f3 ;
}
2001-11-13 17:17:50 +03:00
static struct dev_filter * filter_setup ( struct config_file * cf )
2001-10-23 22:20:27 +04:00
{
const char * lvm_cache ;
struct dev_filter * f3 , * f4 ;
struct stat st ;
2001-12-17 15:01:09 +03:00
char cache_file [ PATH_MAX ] ;
2001-10-23 22:20:27 +04:00
2001-11-14 13:44:14 +03:00
_dump_filter = 0 ;
2001-10-24 21:53:50 +04:00
2001-11-13 17:17:50 +03:00
if ( ! ( f3 = filter_components_setup ( cmd - > cf ) ) )
2001-10-23 22:20:27 +04:00
return 0 ;
2001-12-17 17:05:43 +03:00
if ( lvm_snprintf ( cache_file , sizeof ( cache_file ) ,
2001-12-31 18:20:18 +03:00
" %s/.cache " , _sys_dir ) < 0 ) {
log_error ( " Persistent cache filename too long ('%s/.cache'). " ,
_sys_dir ) ;
2001-12-17 15:01:09 +03:00
return 0 ;
}
2002-02-12 00:00:35 +03:00
lvm_cache = find_config_str ( cf - > root , " devices/cache " , ' / ' , cache_file ) ;
2001-10-23 22:20:27 +04:00
if ( ! ( f4 = persistent_filter_create ( f3 , lvm_cache ) ) ) {
log_error ( " Failed to create persistent device filter " ) ;
2001-10-24 21:53:50 +04:00
return 0 ;
2001-10-23 22:20:27 +04:00
}
2001-10-24 21:53:50 +04:00
/* Should we ever dump persistent filter state? */
2001-11-13 17:17:50 +03:00
if ( find_config_int ( cf - > root , " devices/write_cache_state " , ' / ' , 1 ) )
2001-11-14 13:44:14 +03:00
_dump_filter = 1 ;
2001-11-10 01:01:04 +03:00
2002-01-01 00:27:39 +03:00
if ( ! * _sys_dir )
_dump_filter = 0 ;
2001-10-23 22:20:27 +04:00
if ( ! stat ( lvm_cache , & st ) & & ! persistent_filter_load ( f4 ) )
log_verbose ( " Failed to load existing device cache from %s " ,
lvm_cache ) ;
2001-10-23 15:50:49 +04:00
return f4 ;
}
2002-02-11 23:50:53 +03:00
static struct uuid_map * _init_uuid_map ( struct dev_filter * filter )
2002-01-15 20:37:23 +03:00
{
label_init ( ) ;
/* add in the lvm1 labeller */
if ( ! ( _lvm1_label = lvm1_labeller_create ( ) ) ) {
log_err ( " Couldn't create lvm1 label handler. " ) ;
return 0 ;
}
if ( ! ( label_register_handler ( " lvm1 " , _lvm1_label ) ) ) {
log_err ( " Couldn't register lvm1 label handler. " ) ;
return 0 ;
}
2002-02-11 23:50:53 +03:00
return uuid_map_create ( filter ) ;
2002-01-15 20:37:23 +03:00
}
static void _exit_uuid_map ( void )
{
2002-02-11 23:50:53 +03:00
uuid_map_destroy ( cmd - > um ) ;
2002-01-15 20:37:23 +03:00
label_exit ( ) ;
_lvm1_label - > ops - > destroy ( _lvm1_label ) ;
2002-01-16 00:28:04 +03:00
_lvm1_label = NULL ;
2002-01-15 20:37:23 +03:00
}
2001-12-17 15:01:09 +03:00
static int _get_env_vars ( void )
{
const char * e ;
2002-01-01 00:27:39 +03:00
/* Set to "" to avoid using any system directory */
2001-12-17 15:01:09 +03:00
if ( ( e = getenv ( " LVM_SYSTEM_DIR " ) ) ) {
2001-12-31 18:20:18 +03:00
if ( lvm_snprintf ( _sys_dir , sizeof ( _sys_dir ) , " %s " , e ) < 0 ) {
log_error ( " LVM_SYSTEM_DIR environment variable "
" is too long. " ) ;
2001-12-17 15:01:09 +03:00
return 0 ;
}
}
return 1 ;
}
2001-09-25 16:49:28 +04:00
static int init ( void )
{
struct stat info ;
2002-01-01 00:27:39 +03:00
char config_file [ PATH_MAX ] = " " ;
2002-01-09 22:16:48 +03:00
mode_t old_umask ;
2001-12-17 15:01:09 +03:00
if ( ! _get_env_vars ( ) )
return 0 ;
2001-11-12 18:10:01 +03:00
2002-01-01 00:27:39 +03:00
/* Create system directory if it doesn't already exist */
if ( ! create_dir ( _sys_dir ) )
return 0 ;
2001-11-12 18:10:01 +03:00
if ( ! ( cmd = dbg_malloc ( sizeof ( * cmd ) ) ) ) {
log_error ( " Failed to allocate command context " ) ;
2001-12-17 15:01:09 +03:00
return 0 ;
2001-11-12 18:10:01 +03:00
}
2001-10-08 22:44:22 +04:00
2002-02-11 23:50:53 +03:00
cmd - > args = & the_args [ 0 ] ;
2001-11-13 17:17:50 +03:00
if ( ! ( cmd - > cf = create_config_file ( ) ) ) {
2001-09-25 16:49:28 +04:00
stack ;
2001-12-17 15:01:09 +03:00
return 0 ;
2001-09-25 16:49:28 +04:00
}
/* Use LOG_USER for syslog messages by default */
init_syslog ( LOG_USER ) ;
2002-01-09 22:16:48 +03:00
_init_rand ( ) ;
2002-01-01 00:27:39 +03:00
if ( * _sys_dir & & lvm_snprintf ( config_file , sizeof ( config_file ) ,
" %s/lvm.conf " , _sys_dir ) < 0 ) {
2001-12-31 18:20:18 +03:00
log_error ( " lvm_sys_dir was too long " ) ;
2001-12-17 15:01:09 +03:00
return 0 ;
}
if ( stat ( config_file , & info ) ! = - 1 ) {
2001-09-25 16:49:28 +04:00
/* we've found a config file */
2001-12-17 15:01:09 +03:00
if ( ! read_config ( cmd - > cf , config_file ) ) {
2002-02-12 00:00:35 +03:00
log_error ( " Failed to load config file %s " , config_file ) ;
2001-12-17 15:01:09 +03:00
return 0 ;
2001-09-25 16:49:28 +04:00
}
2001-11-13 17:17:50 +03:00
__init_log ( cmd - > cf ) ;
2001-09-25 16:49:28 +04:00
}
2002-01-15 20:37:23 +03:00
_default_settings . umask = find_config_int ( cmd - > cf - > root ,
2002-02-12 00:00:35 +03:00
" global/umask " , ' / ' ,
DEFAULT_UMASK ) ;
2002-01-09 22:16:48 +03:00
2002-02-12 00:00:35 +03:00
if ( ( old_umask = umask ( ( mode_t ) _default_settings . umask ) ) ! =
( mode_t ) _default_settings . umask )
log_verbose ( " Set umask to %04o " , _default_settings . umask ) ;
2002-01-09 22:16:48 +03:00
2001-12-31 18:20:18 +03:00
if ( lvm_snprintf ( _dev_dir , sizeof ( _dev_dir ) , " %s/ " ,
2002-02-12 00:00:35 +03:00
find_config_str ( cmd - > cf - > root , " devices/dir " ,
2001-12-31 18:20:18 +03:00
' / ' , DEFAULT_DEV_DIR ) ) < 0 ) {
log_error ( " Device directory given in config file too long " ) ;
return 0 ;
}
cmd - > dev_dir = _dev_dir ;
dm_set_dev_dir ( cmd - > dev_dir ) ;
2001-11-21 22:32:35 +03:00
dm_log_init ( print_log ) ;
2002-01-16 02:34:13 +03:00
if ( lvm_snprintf ( _proc_dir , sizeof ( _proc_dir ) , " %s " ,
2002-02-12 00:00:35 +03:00
find_config_str ( cmd - > cf - > root , " global/proc " ,
2002-01-16 02:34:13 +03:00
' / ' , DEFAULT_PROC_DIR ) ) < 0 ) {
log_error ( " Device directory given in config file too long " ) ;
return 0 ;
}
2002-01-07 14:12:11 +03:00
if ( ! _init_backup ( cmd - > cf ) )
2002-01-01 00:27:39 +03:00
return 0 ;
2001-12-17 15:01:09 +03:00
if ( ! dev_cache_setup ( cmd - > cf ) )
return 0 ;
2001-10-08 22:44:22 +04:00
2001-11-13 17:17:50 +03:00
if ( ! ( cmd - > filter = filter_setup ( cmd - > cf ) ) ) {
2001-10-23 15:50:49 +04:00
log_error ( " Failed to set up internal device filters " ) ;
2001-12-17 15:01:09 +03:00
return 0 ;
2001-10-08 22:44:22 +04:00
}
2002-01-15 20:37:23 +03:00
/* the uuid map uses the filter */
2002-02-11 23:50:53 +03:00
if ( ! ( cmd - > um = _init_uuid_map ( cmd - > filter ) ) ) {
2002-01-15 20:37:23 +03:00
log_err ( " Failed to set up the uuid map. " ) ;
return 0 ;
}
2001-11-12 18:10:01 +03:00
if ( ! ( cmd - > mem = pool_create ( 4 * 1024 ) ) ) {
log_error ( " Command pool creation failed " ) ;
2001-12-17 15:01:09 +03:00
return 0 ;
2001-10-02 02:12:10 +04:00
}
2002-02-11 23:50:53 +03:00
if ( ! ( cmd - > fid = create_lvm1_format ( cmd ) ) )
2001-12-17 15:01:09 +03:00
return 0 ;
2001-09-25 16:49:28 +04:00
2002-01-07 14:12:11 +03:00
_use_settings ( & _default_settings ) ;
2001-12-17 15:01:09 +03:00
return 1 ;
2001-09-25 16:49:28 +04:00
}
static void __fin_commands ( void )
{
int i ;
for ( i = 0 ; i < _num_commands ; i + + )
dbg_free ( _commands [ i ] . valid_args ) ;
dbg_free ( _commands ) ;
}
static void fin ( void )
{
2001-11-14 13:44:14 +03:00
if ( _dump_filter )
2001-11-12 18:10:01 +03:00
persistent_filter_dump ( cmd - > filter ) ;
2001-10-24 21:53:50 +04:00
2002-02-11 23:50:53 +03:00
cmd - > fid - > ops - > destroy ( cmd - > fid ) ;
2001-11-12 18:10:01 +03:00
cmd - > filter - > destroy ( cmd - > filter ) ;
pool_destroy ( cmd - > mem ) ;
2001-12-13 03:07:29 +03:00
vgcache_destroy ( ) ;
2001-10-01 23:36:06 +04:00
dev_cache_exit ( ) ;
2001-11-13 17:17:50 +03:00
destroy_config_file ( cmd - > cf ) ;
2002-01-08 21:14:04 +03:00
archive_exit ( ) ;
backup_exit ( ) ;
2002-01-15 21:17:57 +03:00
_exit_uuid_map ( ) ;
2002-02-11 23:50:53 +03:00
dbg_free ( cmd ) ;
2001-09-25 16:49:28 +04:00
__fin_commands ( ) ;
2002-01-15 21:17:57 +03:00
2001-09-25 16:49:28 +04:00
dump_memory ( ) ;
fin_log ( ) ;
2002-01-19 00:26:37 +03:00
fin_syslog ( ) ;
2001-09-25 16:49:28 +04:00
if ( _log )
fclose ( _log ) ;
}
static int run_script ( int argc , char * * argv )
{
FILE * script ;
char buffer [ CMD_LEN ] ;
int ret = 0 ;
int magic_number = 0 ;
if ( ( script = fopen ( argv [ 0 ] , " r " ) ) = = NULL )
2001-10-06 01:39:30 +04:00
return ENO_SUCH_CMD ;
2001-09-25 16:49:28 +04:00
2001-11-10 01:01:04 +03:00
while ( fgets ( buffer , sizeof ( buffer ) , script ) ! = NULL ) {
2001-09-25 16:49:28 +04:00
if ( ! magic_number ) {
if ( buffer [ 0 ] = = ' # ' & & buffer [ 1 ] = = ' ! ' )
magic_number = 1 ;
else
2001-10-06 01:39:30 +04:00
return ENO_SUCH_CMD ;
2001-09-25 16:49:28 +04:00
}
2001-11-10 01:01:04 +03:00
if ( ( strlen ( buffer ) = = sizeof ( buffer ) - 1 )
& & ( buffer [ sizeof ( buffer ) - 1 ] - 2 ! = ' \n ' ) ) {
2001-09-25 16:49:28 +04:00
buffer [ 50 ] = ' \0 ' ;
log_error ( " Line too long (max 255) beginning: %s " ,
buffer ) ;
2001-10-06 01:39:30 +04:00
ret = EINVALID_CMD_LINE ;
2001-09-25 16:49:28 +04:00
break ;
}
if ( split ( buffer , & argc , argv , MAX_ARGS ) = = MAX_ARGS ) {
buffer [ 50 ] = ' \0 ' ;
log_error ( " Too many arguments: %s " , buffer ) ;
2001-10-06 01:39:30 +04:00
ret = EINVALID_CMD_LINE ;
2001-09-25 16:49:28 +04:00
break ;
}
if ( ! argc )
continue ;
2002-01-31 23:08:52 +03:00
if ( ! strcmp ( argv [ 0 ] , " quit " ) | | ! strcmp ( argv [ 0 ] , " exit " ) )
2001-09-25 16:49:28 +04:00
break ;
run_command ( argc , argv ) ;
}
fclose ( script ) ;
return ret ;
}
# ifdef READLINE_SUPPORT
/* List matching commands */
2001-12-17 20:18:47 +03:00
static char * _list_cmds ( const char * text , int state )
2001-09-25 16:49:28 +04:00
{
static int i = 0 ;
static int len = 0 ;
/* Initialise if this is a new completion attempt */
if ( ! state ) {
i = 0 ;
len = strlen ( text ) ;
}
while ( i < _num_commands )
if ( ! strncmp ( text , _commands [ i + + ] . name , len ) )
return strdup ( _commands [ i - 1 ] . name ) ;
return NULL ;
}
/* List matching arguments */
2001-12-17 20:18:47 +03:00
static char * _list_args ( const char * text , int state )
2001-09-25 16:49:28 +04:00
{
static int match_no = 0 ;
static int len = 0 ;
static struct command * com ;
/* Initialise if this is a new completion attempt */
if ( ! state ) {
char * s = rl_line_buffer ;
int j = 0 ;
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 < _num_commands ; j + + ) {
char * p ;
char * q = s ;
p = ( char * ) _commands [ j ] . name ;
while ( * p = = * q ) {
p + + ;
q + + ;
}
if ( ( ! * p ) & & * q = = ' ' ) {
com = _commands + j ;
break ;
}
}
if ( ! com )
return NULL ;
}
/* Short form arguments */
if ( len < 3 ) {
while ( match_no < com - > num_args ) {
char s [ 3 ] ;
char c ;
if ( ! ( c = ( the_args +
com - > valid_args [ match_no + + ] ) - > short_arg ) )
2002-02-12 00:00:35 +03:00
continue ;
2001-09-25 16:49:28 +04:00
sprintf ( s , " -%c " , c ) ;
if ( ! strncmp ( text , s , len ) )
return strdup ( s ) ;
}
}
/* Long form arguments */
if ( match_no < com - > num_args )
match_no = com - > num_args ;
while ( match_no - com - > num_args < com - > num_args ) {
char * l ;
l = ( the_args +
com - > valid_args [ match_no + + - com - > num_args ] ) - > long_arg ;
if ( ! strncmp ( text , l , len ) )
return strdup ( l ) ;
}
return NULL ;
}
2001-12-17 20:18:47 +03:00
/* Custom completion function */
static char * * _completion ( const char * text , int start_pos , int end_pos )
{
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 ;
}
2001-12-17 20:59:58 +03:00
static int _hist_file ( char * buffer , size_t size )
{
char * e = getenv ( " HOME " ) ;
if ( lvm_snprintf ( buffer , size , " %s/.lvm_history " , e ) < 0 ) {
2001-12-31 18:20:18 +03:00
log_error ( " $HOME/.lvm_history: path too long " ) ;
2001-12-17 20:59:58 +03:00
return 0 ;
}
return 1 ;
}
static void _read_history ( void )
{
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 ) ;
2002-02-12 00:00:35 +03:00
stifle_history ( find_config_int ( cmd - > cf - > root , " shell/history_size " ,
2002-01-08 22:17:08 +03:00
' / ' , DEFAULT_MAX_HISTORY ) ) ;
2001-12-31 18:20:18 +03:00
2001-12-17 20:59:58 +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 ) ;
}
2001-09-25 16:49:28 +04:00
static int shell ( void )
{
2001-10-15 16:49:58 +04:00
int argc , ret ;
char * input = NULL , * args [ MAX_ARGS ] , * * argv ;
2001-09-25 16:49:28 +04:00
rl_readline_name = " lvm " ;
2001-12-17 20:18:47 +03:00
rl_attempted_completion_function = ( CPPFunction * ) _completion ;
2001-09-25 16:49:28 +04:00
2001-12-17 20:59:58 +03:00
_read_history ( ) ;
2001-09-25 16:49:28 +04:00
_interactive = 1 ;
while ( 1 ) {
2001-10-15 16:49:58 +04:00
free ( input ) ;
2001-09-25 16:49:28 +04:00
input = readline ( " lvm> " ) ;
/* EOF */
if ( ! input ) {
printf ( " \n " ) ;
break ;
}
/* empty line */
if ( ! * input )
continue ;
add_history ( input ) ;
2001-10-15 16:49:58 +04:00
argv = args ;
2001-09-25 16:49:28 +04:00
if ( split ( input , & argc , argv , MAX_ARGS ) = = MAX_ARGS ) {
log_error ( " Too many arguments, sorry. " ) ;
continue ;
}
2001-10-15 16:49:58 +04:00
if ( ! strcmp ( argv [ 0 ] , " lvm " ) ) {
argv + + ;
argc - - ;
}
2001-09-25 16:49:28 +04:00
if ( ! argc )
continue ;
2002-01-31 23:08:52 +03:00
if ( ! strcmp ( argv [ 0 ] , " quit " ) | | ! strcmp ( argv [ 0 ] , " exit " ) ) {
2001-12-17 20:59:58 +03:00
remove_history ( history_length - 1 ) ;
2001-10-15 16:49:58 +04:00
log_error ( " Exiting. " ) ;
2001-09-25 16:49:28 +04:00
break ;
2001-10-15 16:49:58 +04:00
}
2001-09-25 16:49:28 +04:00
2001-10-15 16:49:58 +04:00
ret = run_command ( argc , argv ) ;
if ( ret = = ENO_SUCH_CMD )
log_error ( " No such command '%s'. Try 'help'. " ,
argv [ 0 ] ) ;
2001-09-25 16:49:28 +04:00
}
2001-12-17 20:59:58 +03:00
_write_history ( ) ;
2001-09-25 16:49:28 +04:00
free ( input ) ;
return 0 ;
}
# endif