2004-03-26 15:00:24 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2009-02-23 00:14:37 +03:00
* Copyright ( C ) 2004 - 2009 Red Hat , Inc . All rights reserved .
2004-05-05 01:25:57 +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
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2004-03-26 15:00:24 +03:00
*/
# include "tools.h"
# include "lvm2cmdline.h"
# include "label.h"
2009-02-23 01:11:58 +03:00
# include "lvm-version.h"
2004-03-26 15:00:24 +03:00
# include "stub.h"
2004-03-26 17:56:41 +03:00
# include "lvm2cmd.h"
2007-10-03 20:10:04 +04:00
# include "last-path-component.h"
2004-03-26 15:00:24 +03:00
# include <signal.h>
# include <syslog.h>
# include <libgen.h>
# include <sys/stat.h>
# include <time.h>
2004-12-10 19:01:35 +03:00
# include <sys/resource.h>
2004-03-26 15:00:24 +03:00
# ifdef HAVE_GETOPTLONG
# include <getopt.h>
# define GETOPTLONG_FN(a, b, c, d, e) getopt_long((a), (b), (c), (d), (e))
# define OPTIND_INIT 0
# else
struct option {
} ;
extern int optind ;
extern char * optarg ;
# define GETOPTLONG_FN(a, b, c, d, e) getopt((a), (b), (c))
# define OPTIND_INIT 1
# endif
2010-03-23 17:43:18 +03:00
# ifdef UDEV_SYNC_SUPPORT
2010-02-15 19:26:48 +03:00
# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
# include <libudev.h>
# endif
2004-03-26 15:00:24 +03:00
/*
2007-02-14 19:51:48 +03:00
* Table of valid switches
2004-03-26 15:00:24 +03:00
*/
2007-02-14 19:51:48 +03:00
static struct arg _the_args [ ARG_COUNT + 1 ] = {
2007-08-21 23:46:36 +04:00
# define arg(a, b, c, d, e) {b, "", "--" c, d, e, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), SIGN_NONE, PERCENT_NONE, NULL},
2004-03-26 15:00:24 +03:00
# include "args.h"
# undef arg
} ;
2007-02-14 19:51:48 +03:00
static struct cmdline_context _cmdline ;
2004-03-26 15:00:24 +03:00
2008-12-17 19:45:32 +03:00
/* Command line args */
2009-11-03 18:50:42 +03:00
/* FIXME: Move static _the_args into cmd? */
2008-12-17 19:46:45 +03:00
unsigned arg_count ( const struct cmd_context * cmd __attribute ( ( unused ) ) , int a )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return _the_args [ a ] . count ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
unsigned arg_is_set ( const struct cmd_context * cmd , int a )
{
return arg_count ( cmd , a ) ? 1 : 0 ;
}
2008-12-17 19:46:45 +03:00
const char * arg_value ( struct cmd_context * cmd __attribute ( ( unused ) ) , int a )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return _the_args [ a ] . value ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
const char * arg_str_value ( struct cmd_context * cmd , int a , const char * def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . value : def ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
int32_t arg_int_value ( struct cmd_context * cmd , int a , const int32_t def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . i_value : def ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
uint32_t arg_uint_value ( struct cmd_context * cmd , int a , const uint32_t def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . ui_value : def ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
int64_t arg_int64_value ( struct cmd_context * cmd , int a , const int64_t def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . i64_value : def ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
uint64_t arg_uint64_value ( struct cmd_context * cmd , int a , const uint64_t def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . ui64_value : def ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
const void * arg_ptr_value ( struct cmd_context * cmd , int a , const void * def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . ptr : def ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
sign_t arg_sign_value ( struct cmd_context * cmd , int a , const sign_t def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . sign : def ;
2008-12-17 19:45:32 +03:00
}
2009-11-03 18:50:42 +03:00
percent_t arg_percent_value ( struct cmd_context * cmd , int a , const percent_t def )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return arg_count ( cmd , a ) ? _the_args [ a ] . percent : def ;
2008-12-17 19:45:32 +03:00
}
2008-12-17 19:46:45 +03:00
int arg_count_increment ( struct cmd_context * cmd __attribute ( ( unused ) ) , int a )
2008-12-17 19:45:32 +03:00
{
2008-12-17 19:46:45 +03:00
return _the_args [ a ] . count + + ;
2008-12-17 19:45:32 +03:00
}
2006-05-10 01:23:51 +04:00
int yes_no_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-03-26 15:00:24 +03:00
{
a - > sign = SIGN_NONE ;
2006-09-26 13:35:43 +04:00
a - > percent = PERCENT_NONE ;
2004-03-26 15:00:24 +03:00
if ( ! strcmp ( a - > value , " y " ) ) {
a - > i_value = 1 ;
a - > ui_value = 1 ;
2004-05-24 17:44:10 +04:00
}
else if ( ! strcmp ( a - > value , " n " ) ) {
a - > i_value = 0 ;
a - > ui_value = 0 ;
}
else
return 0 ;
return 1 ;
}
2006-05-10 01:23:51 +04:00
int yes_no_excl_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct arg * a )
2004-05-24 17:44:10 +04:00
{
a - > sign = SIGN_NONE ;
2006-09-26 13:35:43 +04:00
a - > percent = PERCENT_NONE ;
2004-05-24 17:44:10 +04:00
2004-11-12 18:58:26 +03:00
if ( ! strcmp ( a - > value , " e " ) | | ! strcmp ( a - > value , " ey " ) | |
! strcmp ( a - > value , " ye " ) ) {
2004-06-16 21:13:41 +04:00
a - > i_value = CHANGE_AE ;
a - > ui_value = CHANGE_AE ;
2004-05-24 17:44:10 +04:00
}
else if ( ! strcmp ( a - > value , " y " ) ) {
2004-06-16 21:13:41 +04:00
a - > i_value = CHANGE_AY ;
a - > ui_value = CHANGE_AY ;
2004-03-26 15:00:24 +03:00
}
2004-11-12 18:58:26 +03:00
else if ( ! strcmp ( a - > value , " n " ) | | ! strcmp ( a - > value , " en " ) | |
! strcmp ( a - > value , " ne " ) ) {
2004-06-16 21:13:41 +04:00
a - > i_value = CHANGE_AN ;
a - > ui_value = CHANGE_AN ;
}
else if ( ! strcmp ( a - > value , " ln " ) | | ! strcmp ( a - > value , " nl " ) ) {
a - > i_value = CHANGE_ALN ;
a - > ui_value = CHANGE_ALN ;
}
else if ( ! strcmp ( a - > value , " ly " ) | | ! strcmp ( a - > value , " yl " ) ) {
a - > i_value = CHANGE_ALY ;
a - > ui_value = CHANGE_ALY ;
2004-03-26 15:00:24 +03:00
}
else
return 0 ;
return 1 ;
}
int metadatatype_arg ( struct cmd_context * cmd , struct arg * a )
{
struct format_type * fmt ;
char * format ;
format = a - > value ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( fmt , & cmd - > formats ) {
2004-03-26 15:00:24 +03:00
if ( ! strcasecmp ( fmt - > name , format ) | |
! strcasecmp ( fmt - > name + 3 , format ) | |
( fmt - > alias & & ! strcasecmp ( fmt - > alias , format ) ) ) {
a - > ptr = fmt ;
return 1 ;
}
}
return 0 ;
}
static int _get_int_arg ( struct arg * a , char * * ptr )
{
char * val ;
long v ;
2006-09-26 13:35:43 +04:00
a - > percent = PERCENT_NONE ;
2004-03-26 15:00:24 +03:00
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 ) ;
if ( * ptr = = val )
return 0 ;
a - > i_value = ( int32_t ) v ;
a - > ui_value = ( uint32_t ) v ;
a - > i64_value = ( int64_t ) v ;
a - > ui64_value = ( uint64_t ) v ;
return 1 ;
}
2007-11-14 03:08:25 +03:00
/* Size stored in sectors */
2006-05-10 01:23:51 +04:00
static int _size_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a , int factor )
2004-03-26 15:00:24 +03:00
{
char * ptr ;
int i ;
2009-07-06 23:13:26 +04:00
static const char * suffixes = " kmgtpebs " ;
2004-03-26 15:00:24 +03:00
char * val ;
double v ;
2009-07-06 23:13:26 +04:00
uint64_t v_tmp , adjustment ;
2004-03-26 15:00:24 +03:00
2006-09-26 13:35:43 +04:00
a - > percent = PERCENT_NONE ;
2004-03-26 15:00:24 +03:00
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 = strtod ( val , & ptr ) ;
if ( ptr = = val )
return 0 ;
if ( * ptr ) {
for ( i = strlen ( suffixes ) - 1 ; i > = 0 ; i - - )
if ( suffixes [ i ] = = tolower ( ( int ) * ptr ) )
break ;
2009-07-06 23:13:26 +04:00
if ( i < 0 ) {
2004-03-26 15:00:24 +03:00
return 0 ;
2009-07-06 23:13:26 +04:00
} else if ( i = = 7 ) {
/* sectors */
v = v ;
} else if ( i = = 6 ) {
/* bytes */
v_tmp = ( uint64_t ) v ;
adjustment = v_tmp % 512 ;
if ( adjustment ) {
v_tmp + = ( 512 - adjustment ) ;
log_error ( " Size is not a multiple of 512. "
2009-07-07 05:51:00 +04:00
" Try using % " PRIu64 " or % " PRIu64 " . " ,
2009-07-06 23:13:26 +04:00
v_tmp - 512 , v_tmp ) ;
return 0 ;
}
v / = 512 ;
} else {
/* all other units: kmgtpe */
while ( i - - > 0 )
v * = 1024 ;
v * = 2 ;
}
2004-03-26 15:00:24 +03:00
} else
v * = factor ;
a - > i_value = ( int32_t ) v ;
a - > ui_value = ( uint32_t ) v ;
a - > i64_value = ( int64_t ) v ;
a - > ui64_value = ( uint64_t ) v ;
return 1 ;
}
int size_kb_arg ( struct cmd_context * cmd , struct arg * a )
{
2007-11-14 03:08:25 +03:00
return _size_arg ( cmd , a , 2 ) ;
2004-03-26 15:00:24 +03:00
}
int size_mb_arg ( struct cmd_context * cmd , struct arg * a )
{
2007-11-14 03:08:25 +03:00
return _size_arg ( cmd , a , 2048 ) ;
2004-03-26 15:00:24 +03:00
}
2006-05-10 01:23:51 +04:00
int int_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-03-26 15:00:24 +03:00
{
char * ptr ;
if ( ! _get_int_arg ( a , & ptr ) | | ( * ptr ) | | ( a - > sign = = SIGN_MINUS ) )
return 0 ;
return 1 ;
}
2006-05-10 01:23:51 +04:00
int int_arg_with_sign ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-03-26 15:00:24 +03:00
{
char * ptr ;
if ( ! _get_int_arg ( a , & ptr ) | | ( * ptr ) )
return 0 ;
return 1 ;
}
2006-09-26 13:35:43 +04:00
int int_arg_with_sign_and_percent ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct arg * a )
{
char * ptr ;
if ( ! _get_int_arg ( a , & ptr ) )
return 0 ;
if ( ! * ptr )
return 1 ;
if ( * ptr + + ! = ' % ' )
return 0 ;
if ( ! strcasecmp ( ptr , " V " ) | | ! strcasecmp ( ptr , " VG " ) )
a - > percent = PERCENT_VG ;
else if ( ! strcasecmp ( ptr , " L " ) | | ! strcasecmp ( ptr , " LV " ) )
a - > percent = PERCENT_LV ;
2007-09-21 01:39:08 +04:00
else if ( ! strcasecmp ( ptr , " P " ) | | ! strcasecmp ( ptr , " PV " ) | |
! strcasecmp ( ptr , " PVS " ) )
a - > percent = PERCENT_PVS ;
2006-09-26 13:35:43 +04:00
else if ( ! strcasecmp ( ptr , " F " ) | | ! strcasecmp ( ptr , " FR " ) | |
! strcasecmp ( ptr , " FREE " ) )
a - > percent = PERCENT_FREE ;
2010-02-03 06:58:08 +03:00
else if ( ! strcasecmp ( ptr , " O " ) | | ! strcasecmp ( ptr , " OR " ) | |
! strcasecmp ( ptr , " ORIGIN " ) )
a - > percent = PERCENT_ORIGIN ;
2006-09-26 13:35:43 +04:00
else
return 0 ;
return 1 ;
}
2006-05-10 01:23:51 +04:00
int minor_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-03-26 15:00:24 +03:00
{
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 ;
}
2006-05-10 01:23:51 +04:00
int major_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-03-26 15:00:24 +03:00
{
char * ptr ;
if ( ! _get_int_arg ( a , & ptr ) | | ( * ptr ) | | ( a - > sign = = SIGN_MINUS ) )
return 0 ;
if ( a - > i_value > 255 ) {
log_error ( " Major number outside range 0-255 " ) ;
return 0 ;
}
/* FIXME Also Check against /proc/devices */
return 1 ;
}
2006-05-10 01:23:51 +04:00
int string_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct arg * a __attribute ( ( unused ) ) )
2004-03-26 15:00:24 +03:00
{
return 1 ;
}
2006-05-10 01:23:51 +04:00
int tag_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-03-26 15:00:24 +03:00
{
char * pos = a - > value ;
if ( * pos = = ' @ ' )
pos + + ;
if ( ! validate_name ( pos ) )
return 0 ;
2007-11-16 00:59:11 +03:00
a - > value = pos ;
2004-03-26 15:00:24 +03:00
return 1 ;
}
2006-05-10 01:23:51 +04:00
int permission_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-03-26 15:00:24 +03:00
{
a - > sign = SIGN_NONE ;
if ( ( ! strcmp ( a - > value , " rw " ) ) | | ( ! strcmp ( a - > value , " wr " ) ) )
a - > ui_value = LVM_READ | LVM_WRITE ;
else if ( ! strcmp ( a - > value , " r " ) )
a - > ui_value = LVM_READ ;
else
return 0 ;
return 1 ;
}
2006-05-10 01:23:51 +04:00
int alloc_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
2004-05-19 02:12:53 +04:00
{
alloc_policy_t alloc ;
a - > sign = SIGN_NONE ;
alloc = get_alloc_from_string ( a - > value ) ;
if ( alloc = = ALLOC_INVALID )
return 0 ;
a - > ui_value = ( uint32_t ) alloc ;
return 1 ;
}
2004-05-11 20:01:58 +04:00
int segtype_arg ( struct cmd_context * cmd , struct arg * a )
{
if ( ! ( a - > ptr = ( void * ) get_segtype_from_string ( cmd , a - > value ) ) )
return 0 ;
return 1 ;
}
2007-11-09 19:51:54 +03:00
/*
* Positive integer , zero or " auto " .
*/
int readahead_arg ( struct cmd_context * cmd __attribute ( ( unused ) ) , struct arg * a )
{
if ( ! strcasecmp ( a - > value , " auto " ) ) {
a - > ui_value = DM_READ_AHEAD_AUTO ;
return 1 ;
}
if ( ! strcasecmp ( a - > value , " none " ) ) {
a - > ui_value = DM_READ_AHEAD_NONE ;
return 1 ;
}
2007-11-14 03:08:25 +03:00
if ( ! _size_arg ( cmd , a , 1 ) )
return 0 ;
if ( a - > sign = = SIGN_MINUS )
return 0 ;
return 1 ;
2007-11-09 19:51:54 +03:00
}
2004-03-26 15:00:24 +03:00
static void __alloc ( int size )
{
2007-02-14 19:51:48 +03:00
if ( ! ( _cmdline . commands = dm_realloc ( _cmdline . commands , sizeof ( * _cmdline . commands ) * size ) ) ) {
2004-03-26 15:00:24 +03:00
log_fatal ( " Couldn't allocate memory. " ) ;
exit ( ECMD_FAILED ) ;
}
2007-02-14 19:51:48 +03:00
_cmdline . commands_size = size ;
2004-03-26 15:00:24 +03:00
}
static void _alloc_command ( void )
{
2007-02-14 19:51:48 +03:00
if ( ! _cmdline . commands_size )
2004-03-26 15:00:24 +03:00
__alloc ( 32 ) ;
2007-02-14 19:51:48 +03:00
if ( _cmdline . commands_size < = _cmdline . num_commands )
__alloc ( 2 * _cmdline . commands_size ) ;
2004-03-26 15:00:24 +03:00
}
static void _create_new_command ( const char * name , command_fn command ,
2008-04-03 01:23:39 +04:00
unsigned flags ,
2004-03-26 15:00:24 +03:00
const char * desc , const char * usagestr ,
int nargs , int * args )
{
struct command * nc ;
_alloc_command ( ) ;
2007-02-14 19:51:48 +03:00
nc = _cmdline . commands + _cmdline . num_commands + + ;
2004-03-26 15:00:24 +03:00
nc - > name = name ;
nc - > desc = desc ;
nc - > usage = usagestr ;
nc - > fn = command ;
2008-04-03 01:23:39 +04:00
nc - > flags = flags ;
2004-03-26 15:00:24 +03:00
nc - > num_args = nargs ;
nc - > valid_args = args ;
}
2008-04-03 01:23:39 +04:00
static void _register_command ( const char * name , command_fn fn , const char * desc ,
unsigned flags , const char * usagestr , . . . )
2004-03-26 15:00:24 +03:00
{
int nargs = 0 , i ;
int * args ;
va_list ap ;
/* count how many arguments we have */
va_start ( ap , usagestr ) ;
while ( va_arg ( ap , int ) > = 0 )
nargs + + ;
va_end ( ap ) ;
/* allocate space for them */
2005-10-17 03:03:59 +04:00
if ( ! ( args = dm_malloc ( sizeof ( * args ) * nargs ) ) ) {
2004-03-26 15:00:24 +03:00
log_fatal ( " Out of memory. " ) ;
exit ( ECMD_FAILED ) ;
}
/* fill them in */
va_start ( ap , usagestr ) ;
for ( i = 0 ; i < nargs ; i + + )
args [ i ] = va_arg ( ap , int ) ;
va_end ( ap ) ;
/* enter the command in the register */
2008-04-03 01:23:39 +04:00
_create_new_command ( name , fn , flags , desc , usagestr , nargs , args ) ;
2004-03-26 15:00:24 +03:00
}
2006-08-19 01:17:18 +04:00
void lvm_register_commands ( void )
2004-03-26 15:00:24 +03:00
{
2008-04-03 01:23:39 +04:00
# define xx(a, b, c, d...) _register_command(# a, a, b, c, ## d, \
driverloaded_ARG , \
debug_ARG , help_ARG , help2_ARG , \
version_ARG , verbose_ARG , \
quiet_ARG , config_ARG , - 1 ) ;
2004-03-26 15:00:24 +03:00
# include "commands.h"
# undef xx
}
static struct command * _find_command ( const char * name )
{
int i ;
2008-11-12 12:53:33 +03:00
const char * base ;
2004-03-26 15:00:24 +03:00
2007-07-20 19:48:39 +04:00
base = last_path_component ( name ) ;
2004-03-26 15:00:24 +03:00
2007-02-14 19:51:48 +03:00
for ( i = 0 ; i < _cmdline . num_commands ; i + + ) {
if ( ! strcmp ( base , _cmdline . commands [ i ] . name ) )
2004-03-26 15:00:24 +03:00
break ;
}
2007-02-14 19:51:48 +03:00
if ( i > = _cmdline . num_commands )
2004-03-26 15:00:24 +03:00
return 0 ;
2007-02-14 19:51:48 +03:00
return _cmdline . commands + i ;
2004-03-26 15:00:24 +03:00
}
2007-09-21 22:06:33 +04:00
static void _short_usage ( const char * name )
{
2007-09-21 22:43:55 +04:00
log_error ( " Run `%s --help' for more information. " , name ) ;
2007-09-21 22:06:33 +04:00
}
2008-12-19 17:43:02 +03:00
static int _usage ( const char * name )
2004-03-26 15:00:24 +03:00
{
struct command * com = _find_command ( name ) ;
2008-12-19 17:43:02 +03:00
if ( ! com ) {
log_print ( " %s: no such command. " , name ) ;
return 0 ;
}
2004-03-26 15:00:24 +03:00
2007-09-21 22:06:56 +04:00
log_print ( " %s: %s \n \n %s " , com - > name , com - > desc , com - > usage ) ;
2008-12-19 17:43:02 +03:00
return 1 ;
2004-03-26 15:00:24 +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 .
*/
static void _add_getopt_arg ( int arg , char * * ptr , struct option * * o )
{
2007-02-14 19:51:48 +03:00
struct arg * a = _cmdline . the_args + arg ;
2004-03-26 15:00:24 +03:00
if ( a - > short_arg ) {
* ( * ptr ) + + = a - > short_arg ;
if ( a - > fn )
* ( * ptr ) + + = ' : ' ;
}
# ifdef HAVE_GETOPTLONG
if ( * ( a - > long_arg + 2 ) ) {
( * o ) - > name = a - > long_arg + 2 ;
( * o ) - > has_arg = a - > fn ? 1 : 0 ;
( * o ) - > flag = NULL ;
if ( a - > short_arg )
( * o ) - > val = a - > short_arg ;
else
( * o ) - > val = arg ;
( * o ) + + ;
}
# endif
}
static struct arg * _find_arg ( struct command * com , int opt )
{
struct arg * a ;
int i , arg ;
for ( i = 0 ; i < com - > num_args ; i + + ) {
arg = com - > valid_args [ i ] ;
2007-02-14 19:51:48 +03:00
a = _cmdline . the_args + arg ;
2004-03-26 15:00:24 +03:00
/*
* opt should equal either the
* short arg , or the index into
2007-02-14 19:51:48 +03:00
* the_args .
2004-03-26 15:00:24 +03:00
*/
if ( ( a - > short_arg & & ( opt = = a - > short_arg ) ) | |
( ! a - > short_arg & & ( opt = = arg ) ) )
return a ;
}
return 0 ;
}
static int _process_command_line ( struct cmd_context * cmd , 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 + + ) {
2007-02-14 19:51:48 +03:00
a = _cmdline . the_args + i ;
2004-03-26 15:00:24 +03:00
/* zero the count and arg */
a - > count = 0 ;
a - > value = 0 ;
a - > i_value = 0 ;
a - > ui_value = 0 ;
a - > i64_value = 0 ;
a - > ui64_value = 0 ;
}
/* fill in the short and long opts */
for ( i = 0 ; i < cmd - > command - > num_args ; i + + )
_add_getopt_arg ( cmd - > command - > valid_args [ i ] , & ptr , & o ) ;
* ptr = ' \0 ' ;
memset ( o , 0 , sizeof ( * o ) ) ;
/* initialise getopt_long & scan for command line switches */
optarg = 0 ;
optind = OPTIND_INIT ;
while ( ( opt = GETOPTLONG_FN ( * argc , * argv , str , opts , NULL ) ) > = 0 ) {
if ( opt = = ' ? ' )
return 0 ;
a = _find_arg ( cmd - > command , opt ) ;
if ( ! a ) {
log_fatal ( " Unrecognised option. " ) ;
return 0 ;
}
2007-08-21 23:46:36 +04:00
if ( a - > count & & ! ( a - > flags & ARG_REPEATABLE ) ) {
log_error ( " Option%s%c%s%s may not be repeated " ,
a - > short_arg ? " - " : " " ,
a - > short_arg ? : ' ' ,
( a - > short_arg & & a - > long_arg ) ?
" / " : " " , a - > long_arg ? : " " ) ;
return 0 ;
}
2004-03-26 15:00:24 +03:00
2007-08-21 23:46:36 +04:00
if ( a - > fn ) {
2004-03-26 15:00:24 +03:00
if ( ! optarg ) {
log_error ( " Option requires argument. " ) ;
return 0 ;
}
a - > value = optarg ;
if ( ! a - > fn ( cmd , a ) ) {
log_error ( " Invalid argument %s " , optarg ) ;
return 0 ;
}
}
a - > count + + ;
}
* argc - = optind ;
* argv + = optind ;
return 1 ;
}
static int _merge_synonym ( struct cmd_context * cmd , int oldarg , int newarg )
{
const struct arg * old ;
struct arg * new ;
if ( arg_count ( cmd , oldarg ) & & arg_count ( cmd , newarg ) ) {
log_error ( " %s and %s are synonyms. Please only supply one. " ,
2007-02-14 19:51:48 +03:00
_cmdline . the_args [ oldarg ] . long_arg , _cmdline . the_args [ newarg ] . long_arg ) ;
2004-03-26 15:00:24 +03:00
return 0 ;
}
if ( ! arg_count ( cmd , oldarg ) )
return 1 ;
2007-02-14 19:51:48 +03:00
old = _cmdline . the_args + oldarg ;
new = _cmdline . the_args + newarg ;
2004-03-26 15:00:24 +03:00
new - > count = old - > count ;
new - > value = old - > value ;
new - > i_value = old - > i_value ;
new - > ui_value = old - > ui_value ;
new - > i64_value = old - > i64_value ;
new - > ui64_value = old - > ui64_value ;
new - > sign = old - > sign ;
return 1 ;
}
2006-05-10 01:23:51 +04:00
int version ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
int argc __attribute ( ( unused ) ) ,
char * * argv __attribute ( ( unused ) ) )
2004-03-26 15:00:24 +03:00
{
char vsn [ 80 ] ;
log_print ( " LVM version: %s " , LVM_VERSION ) ;
if ( library_version ( vsn , sizeof ( vsn ) ) )
log_print ( " Library version: %s " , vsn ) ;
if ( driver_version ( vsn , sizeof ( vsn ) ) )
log_print ( " Driver version: %s " , vsn ) ;
return ECMD_PROCESSED ;
}
static int _get_settings ( struct cmd_context * cmd )
{
cmd - > current_settings = cmd - > default_settings ;
if ( arg_count ( cmd , debug_ARG ) )
cmd - > current_settings . debug = _LOG_FATAL +
( arg_count ( cmd , debug_ARG ) - 1 ) ;
if ( arg_count ( cmd , verbose_ARG ) )
cmd - > current_settings . verbose = arg_count ( cmd , verbose_ARG ) ;
if ( arg_count ( cmd , quiet_ARG ) ) {
cmd - > current_settings . debug = 0 ;
cmd - > current_settings . verbose = 0 ;
}
if ( arg_count ( cmd , test_ARG ) )
cmd - > current_settings . test = arg_count ( cmd , test_ARG ) ;
if ( arg_count ( cmd , driverloaded_ARG ) ) {
cmd - > current_settings . activation =
arg_int_value ( cmd , driverloaded_ARG ,
cmd - > default_settings . activation ) ;
}
2006-11-14 18:28:50 +03:00
cmd - > current_settings . archive = arg_int_value ( cmd , autobackup_ARG , cmd - > current_settings . archive ) ;
cmd - > current_settings . backup = arg_int_value ( cmd , autobackup_ARG , cmd - > current_settings . backup ) ;
2008-04-03 01:23:39 +04:00
cmd - > current_settings . cache_vgmetadata = cmd - > command - > flags & CACHE_VGMETADATA ? 1 : 0 ;
2008-09-19 11:12:45 +04:00
cmd - > partial_activation = 0 ;
2004-03-26 15:00:24 +03:00
if ( arg_count ( cmd , partial_ARG ) ) {
2008-09-19 11:12:45 +04:00
cmd - > partial_activation = 1 ;
2004-03-26 15:00:24 +03:00
log_print ( " Partial mode. Incomplete volume groups will "
" be activated read-only. " ) ;
2008-09-19 10:42:00 +04:00
}
2004-03-26 15:00:24 +03:00
if ( arg_count ( cmd , ignorelockingfailure_ARG ) )
init_ignorelockingfailure ( 1 ) ;
else
init_ignorelockingfailure ( 0 ) ;
if ( arg_count ( cmd , nosuffix_ARG ) )
cmd - > current_settings . suffix = 0 ;
if ( arg_count ( cmd , units_ARG ) )
if ( ! ( cmd - > current_settings . unit_factor =
units_to_bytes ( arg_str_value ( cmd , units_ARG , " " ) ,
& cmd - > current_settings . unit_type ) ) ) {
log_error ( " Invalid units specification " ) ;
return EINVALID_CMD_LINE ;
}
2006-08-01 18:56:33 +04:00
if ( arg_count ( cmd , trustcache_ARG ) ) {
if ( arg_count ( cmd , all_ARG ) ) {
log_error ( " --trustcache is incompatible with --all " ) ;
return EINVALID_CMD_LINE ;
}
init_trust_cache ( 1 ) ;
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Cache file of PVs will be trusted. "
2006-08-01 18:56:33 +04:00
" New devices holding PVs may get ignored. " ) ;
} else
init_trust_cache ( 0 ) ;
2009-08-04 19:36:13 +04:00
if ( arg_count ( cmd , noudevsync_ARG ) )
cmd - > current_settings . udev_sync = 0 ;
2004-03-26 15:00:24 +03:00
/* Handle synonyms */
if ( ! _merge_synonym ( cmd , resizable_ARG , resizeable_ARG ) | |
! _merge_synonym ( cmd , allocation_ARG , allocatable_ARG ) | |
2009-05-27 20:30:29 +04:00
! _merge_synonym ( cmd , allocation_ARG , resizeable_ARG ) | |
2009-10-06 00:55:56 +04:00
! _merge_synonym ( cmd , virtualoriginsize_ARG , virtualsize_ARG ) | |
! _merge_synonym ( cmd , metadatacopies_ARG , pvmetadatacopies_ARG ) )
2004-03-26 15:00:24 +03:00
return EINVALID_CMD_LINE ;
/* Zero indicates success */
return 0 ;
}
static int _process_common_commands ( struct cmd_context * cmd )
{
if ( arg_count ( cmd , help_ARG ) | | arg_count ( cmd , help2_ARG ) ) {
_usage ( cmd - > command - > name ) ;
return ECMD_PROCESSED ;
}
if ( arg_count ( cmd , version_ARG ) ) {
return version ( cmd , 0 , ( char * * ) NULL ) ;
}
/* Zero indicates it's OK to continue processing this command */
return 0 ;
}
static void _display_help ( void )
{
int i ;
log_error ( " Available lvm commands: " ) ;
log_error ( " Use 'lvm help <command>' for more information " ) ;
log_error ( " " ) ;
2007-02-14 19:51:48 +03:00
for ( i = 0 ; i < _cmdline . num_commands ; i + + ) {
struct command * com = _cmdline . commands + i ;
2004-03-26 15:00:24 +03:00
log_error ( " %-16.16s%s " , com - > name , com - > desc ) ;
}
}
2006-05-10 01:23:51 +04:00
int help ( struct cmd_context * cmd __attribute ( ( unused ) ) , int argc , char * * argv )
2004-03-26 15:00:24 +03:00
{
2008-12-19 17:43:02 +03:00
int ret = ECMD_PROCESSED ;
2004-03-26 15:00:24 +03:00
if ( ! argc )
_display_help ( ) ;
else {
int i ;
for ( i = 0 ; i < argc ; i + + )
2008-12-19 17:43:02 +03:00
if ( ! _usage ( argv [ i ] ) )
ret = EINVALID_CMD_LINE ;
2004-03-26 15:00:24 +03:00
}
2008-12-19 17:43:02 +03:00
return ret ;
2004-03-26 15:00:24 +03:00
}
static void _apply_settings ( struct cmd_context * cmd )
{
init_debug ( cmd - > current_settings . debug ) ;
init_verbose ( cmd - > current_settings . verbose + VERBOSE_BASE_LEVEL ) ;
init_test ( cmd - > current_settings . test ) ;
2005-03-22 01:40:35 +03:00
init_full_scan_done ( 0 ) ;
2006-05-16 20:48:31 +04:00
init_mirror_in_sync ( 0 ) ;
2004-03-26 15:00:24 +03:00
init_msg_prefix ( cmd - > default_settings . msg_prefix ) ;
init_cmd_name ( cmd - > default_settings . cmd_name ) ;
2005-05-17 17:46:38 +04:00
archive_enable ( cmd , cmd - > current_settings . archive ) ;
backup_enable ( cmd , cmd - > current_settings . backup ) ;
2004-03-26 15:00:24 +03:00
set_activation ( cmd - > current_settings . activation ) ;
cmd - > fmt = arg_ptr_value ( cmd , metadatatype_ARG ,
cmd - > current_settings . fmt ) ;
2008-09-19 10:42:00 +04:00
cmd - > handles_missing_pvs = 0 ;
2004-03-26 15:00:24 +03:00
}
2010-02-15 19:26:48 +03:00
static int _set_udev_checking ( struct cmd_context * cmd )
2010-01-11 18:40:03 +03:00
{
2010-03-23 18:13:03 +03:00
# ifdef UDEV_SYNC_SUPPORT
2010-02-15 19:26:48 +03:00
struct udev * udev ;
const char * udev_dev_dir ;
size_t udev_dev_dir_len ;
int dirs_diff ;
if ( ! ( udev = udev_new ( ) ) | |
! ( udev_dev_dir = udev_get_dev_path ( udev ) ) | |
! * udev_dev_dir ) {
log_error ( " Could not get udev dev path. " ) ;
return 0 ;
}
udev_dev_dir_len = strlen ( udev_dev_dir ) ;
2010-01-11 18:40:03 +03:00
2010-02-15 19:26:48 +03:00
/* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
if ( udev_dev_dir [ udev_dev_dir_len - 1 ] ! = ' / ' )
dirs_diff = strncmp ( cmd - > dev_dir , udev_dev_dir ,
udev_dev_dir_len ) ;
else
dirs_diff = strcmp ( cmd - > dev_dir , udev_dev_dir ) ;
if ( dirs_diff ) {
log_debug ( " The path %s used for creating device nodes and "
" symlinks that is set in the configuration differs "
" from the path %s that is used by udev. All warnings "
" about udev not working correctly while processing "
" particular nodes and symlinks will be suppressed. "
" These nodes and symlinks will be managed in each "
" directory separately. " ,
cmd - > dev_dir , udev_dev_dir ) ;
2010-01-11 18:40:03 +03:00
dm_udev_set_checking ( 0 ) ;
init_udev_checking ( 0 ) ;
2010-02-15 19:26:48 +03:00
}
udev_unref ( udev ) ;
# endif
return 1 ;
2010-01-11 18:40:03 +03:00
}
2009-07-13 23:49:48 +04:00
static const char * _copy_command_line ( struct cmd_context * cmd , int argc , char * * argv )
2004-03-26 15:00:24 +03:00
{
2006-05-16 20:48:31 +04:00
int i , space ;
2004-03-26 15:00:24 +03:00
/*
* Build up the complete command line , used as a
* description for backups .
*/
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_begin_object ( cmd - > mem , 128 ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2004-03-26 15:00:24 +03:00
for ( i = 0 ; i < argc ; i + + ) {
2006-05-16 20:48:31 +04:00
space = strchr ( argv [ i ] , ' ' ) ? 1 : 0 ;
if ( space & & ! dm_pool_grow_object ( cmd - > mem , " ' " , 1 ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2006-05-16 20:48:31 +04:00
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( cmd - > mem , argv [ i ] , strlen ( argv [ i ] ) ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2004-03-26 15:00:24 +03:00
2006-05-16 20:48:31 +04:00
if ( space & & ! dm_pool_grow_object ( cmd - > mem , " ' " , 1 ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2006-05-16 20:48:31 +04:00
2004-03-26 15:00:24 +03:00
if ( i < ( argc - 1 ) )
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( cmd - > mem , " " , 1 ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2004-03-26 15:00:24 +03:00
}
/*
* Terminate .
*/
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( cmd - > mem , " \0 " , 1 ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2004-03-26 15:00:24 +03:00
2005-10-17 03:03:59 +04:00
return dm_pool_end_object ( cmd - > mem ) ;
2004-03-26 15:00:24 +03:00
bad :
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't copy command line. " ) ;
2005-10-17 03:03:59 +04:00
dm_pool_abandon_object ( cmd - > mem ) ;
2004-03-26 15:00:24 +03:00
return NULL ;
}
2006-08-19 01:17:18 +04:00
int lvm_run_command ( struct cmd_context * cmd , int argc , char * * argv )
2004-03-26 15:00:24 +03:00
{
int ret = 0 ;
int locking_type ;
2008-06-06 23:28:35 +04:00
init_error_message_produced ( 0 ) ;
2007-06-15 14:11:14 +04:00
/* each command should start out with sigint flag cleared */
sigint_clear ( ) ;
2009-09-15 02:47:49 +04:00
if ( ! ( cmd - > cmd_line = _copy_command_line ( cmd , argc , argv ) ) ) {
stack ;
2004-03-26 15:00:24 +03:00
return ECMD_FAILED ;
2009-09-15 02:47:49 +04:00
}
2004-03-26 15:00:24 +03:00
2004-12-10 19:01:35 +03:00
log_debug ( " Parsing: %s " , cmd - > cmd_line ) ;
2004-03-26 15:00:24 +03:00
if ( ! ( cmd - > command = _find_command ( argv [ 0 ] ) ) )
return ENO_SUCH_CMD ;
if ( ! _process_command_line ( cmd , & argc , & argv ) ) {
log_error ( " Error during parsing of command line. " ) ;
return EINVALID_CMD_LINE ;
}
set_cmd_name ( cmd - > command - > name ) ;
2006-05-16 20:48:31 +04:00
if ( arg_count ( cmd , config_ARG ) )
2009-07-28 01:01:56 +04:00
if ( ( ret = override_config_tree_from_string ( cmd ,
arg_str_value ( cmd , config_ARG , " " ) ) ) ) {
ret = EINVALID_CMD_LINE ;
2006-05-16 20:48:31 +04:00
goto_out ;
2009-07-28 01:01:56 +04:00
}
2006-05-16 20:48:31 +04:00
if ( arg_count ( cmd , config_ARG ) | | ! cmd - > config_valid | | config_files_changed ( cmd ) ) {
2004-03-26 15:00:24 +03:00
/* Reinitialise various settings inc. logging, filters */
if ( ! refresh_toolcontext ( cmd ) ) {
log_error ( " Updated config file invalid. Aborting. " ) ;
return ECMD_FAILED ;
}
}
if ( ( ret = _get_settings ( cmd ) ) )
2006-05-16 20:48:31 +04:00
goto_out ;
2004-03-26 15:00:24 +03:00
_apply_settings ( cmd ) ;
2004-12-10 19:01:35 +03:00
log_debug ( " Processing: %s " , cmd - > cmd_line ) ;
# ifdef O_DIRECT_SUPPORT
log_debug ( " O_DIRECT will be used " ) ;
# endif
2010-02-15 19:26:48 +03:00
if ( ! _set_udev_checking ( cmd ) )
goto_out ;
2010-01-11 18:40:03 +03:00
2004-03-26 15:00:24 +03:00
if ( ( ret = _process_common_commands ( cmd ) ) )
2006-05-16 20:48:31 +04:00
goto_out ;
2004-03-26 15:00:24 +03:00
2004-03-26 15:09:33 +03:00
if ( arg_count ( cmd , nolocking_ARG ) )
locking_type = 0 ;
else
2009-02-03 19:23:19 +03:00
locking_type = - 1 ;
2004-03-26 15:09:33 +03:00
2006-05-16 20:48:31 +04:00
if ( ! init_locking ( locking_type , cmd ) ) {
2004-03-26 15:00:24 +03:00
ret = ECMD_FAILED ;
goto out ;
}
ret = cmd - > command - > fn ( cmd , argc , argv ) ;
fin_locking ( ) ;
out :
if ( test_mode ( ) ) {
log_verbose ( " Test mode: Wiping internal cache " ) ;
2008-04-08 16:49:21 +04:00
lvmcache_destroy ( cmd , 1 ) ;
2004-03-26 15:00:24 +03:00
}
2006-05-16 20:48:31 +04:00
if ( cmd - > cft_override ) {
destroy_config_tree ( cmd - > cft_override ) ;
cmd - > cft_override = NULL ;
/* Move this? */
if ( ! refresh_toolcontext ( cmd ) )
stack ;
}
2008-01-30 17:00:02 +03:00
2006-05-16 20:48:31 +04:00
/* FIXME Move this? */
2004-03-26 15:00:24 +03:00
cmd - > current_settings = cmd - > default_settings ;
_apply_settings ( cmd ) ;
2007-02-14 19:51:48 +03:00
if ( ret = = EINVALID_CMD_LINE & & ! _cmdline . interactive )
2007-09-21 22:06:33 +04:00
_short_usage ( cmd - > command - > name ) ;
2004-03-26 15:00:24 +03:00
2006-05-16 20:48:31 +04:00
log_debug ( " Completed: %s " , cmd - > cmd_line ) ;
2009-04-02 18:59:48 +04:00
/*
* free off any memory the command used .
*/
dm_pool_empty ( cmd - > mem ) ;
2009-07-16 03:57:54 +04:00
reset_lvm_errno ( 1 ) ;
2004-03-26 15:00:24 +03:00
return ret ;
}
2010-01-11 22:19:17 +03:00
int lvm_return_code ( int ret )
{
return ( ret = = ECMD_PROCESSED ? 0 : ret ) ;
}
2006-08-19 01:17:18 +04:00
int lvm_split ( char * str , int * argc , char * * argv , int max )
2004-03-26 15:00:24 +03:00
{
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 ;
}
2008-08-01 23:51:27 +04:00
static const char * _get_cmdline ( pid_t pid )
{
static char _proc_cmdline [ 32 ] ;
char buf [ 256 ] ;
int fd ;
snprintf ( buf , sizeof ( buf ) , DEFAULT_PROC_DIR " /%u/cmdline " , pid ) ;
if ( ( fd = open ( buf , O_RDONLY ) ) > 0 ) {
read ( fd , _proc_cmdline , sizeof ( _proc_cmdline ) - 1 ) ;
_proc_cmdline [ sizeof ( _proc_cmdline ) - 1 ] = ' \0 ' ;
close ( fd ) ;
} else
_proc_cmdline [ 0 ] = ' \0 ' ;
return _proc_cmdline ;
}
static const char * _get_filename ( int fd )
{
static char filename [ PATH_MAX ] ;
char buf [ 32 ] ; /* Assumes short DEFAULT_PROC_DIR */
int size ;
snprintf ( buf , sizeof ( buf ) , DEFAULT_PROC_DIR " /self/fd/%u " , fd ) ;
if ( ( size = readlink ( buf , filename , sizeof ( filename ) - 1 ) ) = = - 1 )
filename [ 0 ] = ' \0 ' ;
else
filename [ size ] = ' \0 ' ;
return filename ;
}
static void _close_descriptor ( int fd , unsigned suppress_warnings ,
const char * command , pid_t ppid ,
const char * parent_cmdline )
{
int r ;
const char * filename ;
/* Ignore bad file descriptors */
if ( fcntl ( fd , F_GETFD ) = = - 1 & & errno = = EBADF )
return ;
if ( ! suppress_warnings )
filename = _get_filename ( fd ) ;
r = close ( fd ) ;
if ( suppress_warnings )
return ;
if ( ! r )
fprintf ( stderr , " File descriptor %d (%s) leaked on "
" %s invocation. " , fd , filename , command ) ;
else if ( errno = = EBADF )
return ;
else
fprintf ( stderr , " Close failed on stray file descriptor "
" %d (%s): %s " , fd , filename , strerror ( errno ) ) ;
fprintf ( stderr , " Parent PID % " PRIpid_t " : %s \n " , ppid , parent_cmdline ) ;
}
static void _close_stray_fds ( const char * command )
2004-12-10 19:01:35 +03:00
{
struct rlimit rlim ;
int fd ;
2008-08-01 23:51:27 +04:00
unsigned suppress_warnings = 0 ;
pid_t ppid = getppid ( ) ;
const char * parent_cmdline = _get_cmdline ( ppid ) ;
2004-12-10 19:01:35 +03:00
if ( getrlimit ( RLIMIT_NOFILE , & rlim ) < 0 ) {
fprintf ( stderr , " getrlimit(RLIMIT_NOFILE) failed: %s \n " ,
strerror ( errno ) ) ;
return ;
}
2005-03-04 01:09:20 +03:00
if ( getenv ( " LVM_SUPPRESS_FD_WARNINGS " ) )
suppress_warnings = 1 ;
2008-08-01 23:51:27 +04:00
for ( fd = 3 ; fd < rlim . rlim_cur ; fd + + )
_close_descriptor ( fd , suppress_warnings , command , ppid ,
parent_cmdline ) ;
2004-12-10 19:01:35 +03:00
}
2008-12-18 08:27:17 +03:00
struct cmd_context * init_lvm ( void )
2004-03-26 15:00:24 +03:00
{
struct cmd_context * cmd ;
2007-02-14 19:51:48 +03:00
_cmdline . the_args = & _the_args [ 0 ] ;
2009-02-23 00:14:37 +03:00
if ( ! ( cmd = create_toolcontext ( 0 , NULL ) ) )
2008-01-30 16:19:47 +03:00
return_NULL ;
2004-03-26 15:00:24 +03:00
2009-07-16 04:36:59 +04:00
if ( stored_errno ( ) ) {
destroy_toolcontext ( cmd ) ;
return_NULL ;
}
2004-03-26 15:00:24 +03:00
return cmd ;
}
2006-05-10 01:23:51 +04:00
static void _fin_commands ( void )
2004-03-26 15:00:24 +03:00
{
int i ;
2007-02-14 19:51:48 +03:00
for ( i = 0 ; i < _cmdline . num_commands ; i + + )
dm_free ( _cmdline . commands [ i ] . valid_args ) ;
2004-03-26 15:00:24 +03:00
2007-02-14 19:51:48 +03:00
dm_free ( _cmdline . commands ) ;
2010-01-21 16:41:39 +03:00
_cmdline . commands = NULL ;
_cmdline . num_commands = 0 ;
_cmdline . commands_size = 0 ;
2004-03-26 15:00:24 +03:00
}
2006-08-19 01:17:18 +04:00
void lvm_fin ( struct cmd_context * cmd )
2004-03-26 15:00:24 +03:00
{
2006-05-10 01:23:51 +04:00
_fin_commands ( ) ;
2004-03-26 15:00:24 +03:00
destroy_toolcontext ( cmd ) ;
}
static int _run_script ( struct cmd_context * cmd , int argc , char * * argv )
{
FILE * script ;
char buffer [ CMD_LEN ] ;
int ret = 0 ;
int magic_number = 0 ;
2007-01-25 17:37:48 +03:00
char * script_file = argv [ 0 ] ;
2004-03-26 15:00:24 +03:00
2007-01-25 17:37:48 +03:00
if ( ( script = fopen ( script_file , " r " ) ) = = NULL )
2004-03-26 15:00:24 +03:00
return ENO_SUCH_CMD ;
while ( fgets ( buffer , sizeof ( buffer ) , script ) ! = NULL ) {
if ( ! magic_number ) {
if ( buffer [ 0 ] = = ' # ' & & buffer [ 1 ] = = ' ! ' )
magic_number = 1 ;
2006-05-10 01:23:51 +04:00
else {
ret = ENO_SUCH_CMD ;
break ;
}
2004-03-26 15:00:24 +03:00
}
if ( ( strlen ( buffer ) = = sizeof ( buffer ) - 1 )
& & ( buffer [ sizeof ( buffer ) - 1 ] - 2 ! = ' \n ' ) ) {
buffer [ 50 ] = ' \0 ' ;
log_error ( " Line too long (max 255) beginning: %s " ,
buffer ) ;
ret = EINVALID_CMD_LINE ;
break ;
}
2006-08-19 01:17:18 +04:00
if ( lvm_split ( buffer , & argc , argv , MAX_ARGS ) = = MAX_ARGS ) {
2004-03-26 15:00:24 +03:00
buffer [ 50 ] = ' \0 ' ;
log_error ( " Too many arguments: %s " , buffer ) ;
ret = EINVALID_CMD_LINE ;
break ;
}
if ( ! argc )
continue ;
if ( ! strcmp ( argv [ 0 ] , " quit " ) | | ! strcmp ( argv [ 0 ] , " exit " ) )
break ;
2008-06-06 23:28:35 +04:00
ret = lvm_run_command ( cmd , argc , argv ) ;
if ( ret ! = ECMD_PROCESSED ) {
if ( ! 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 ) ;
}
break ;
}
2004-03-26 15:00:24 +03:00
}
2007-01-25 17:37:48 +03:00
if ( fclose ( script ) )
log_sys_error ( " fclose " , script_file ) ;
2004-03-26 15:00:24 +03:00
return ret ;
}
2004-04-08 19:23:23 +04:00
/*
* Determine whether we should fall back and exec the equivalent LVM1 tool
*/
static int _lvm1_fallback ( struct cmd_context * cmd )
{
char vsn [ 80 ] ;
int dm_present ;
2006-05-16 20:48:31 +04:00
if ( ! find_config_tree_int ( cmd , " global/fallback_to_lvm1 " ,
2004-04-08 19:23:23 +04:00
DEFAULT_FALLBACK_TO_LVM1 ) | |
strncmp ( cmd - > kernel_vsn , " 2.4. " , 4 ) )
return 0 ;
log_suppress ( 1 ) ;
dm_present = driver_version ( vsn , sizeof ( vsn ) ) ;
log_suppress ( 0 ) ;
if ( dm_present | | ! lvm1_present ( cmd ) )
return 0 ;
return 1 ;
}
2006-05-10 01:23:51 +04:00
static void _exec_lvm1_command ( char * * argv )
2004-04-08 19:23:23 +04:00
{
char path [ PATH_MAX ] ;
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( path , sizeof ( path ) , " %s.lvm1 " , argv [ 0 ] ) < 0 ) {
2004-04-08 19:23:23 +04:00
log_error ( " Failed to create LVM1 tool pathname " ) ;
return ;
}
execvp ( path , argv ) ;
log_sys_error ( " execvp " , path ) ;
}
2008-11-12 12:49:06 +03:00
static void _nonroot_warning ( void )
2008-01-09 18:55:44 +03:00
{
if ( getuid ( ) | | geteuid ( ) )
log_warn ( " WARNING: Running as a non-root user. Functionality may be unavailable. " ) ;
}
2008-12-18 08:27:17 +03:00
int lvm2_main ( int argc , char * * argv )
2004-03-26 15:00:24 +03:00
{
2008-11-18 13:13:23 +03:00
const char * base ;
2004-03-26 15:00:24 +03:00
int ret , alias = 0 ;
struct cmd_context * cmd ;
2007-07-20 19:48:39 +04:00
base = last_path_component ( argv [ 0 ] ) ;
2004-06-29 17:27:19 +04:00
if ( strcmp ( base , " lvm " ) & & strcmp ( base , " lvm.static " ) & &
strcmp ( base , " initrd-lvm " ) )
2004-03-26 15:00:24 +03:00
alias = 1 ;
2005-02-18 21:58:31 +03:00
2008-08-01 23:51:27 +04:00
_close_stray_fds ( base ) ;
2008-12-18 08:27:17 +03:00
if ( is_static ( ) & & strcmp ( base , " lvm.static " ) & &
2005-02-18 21:58:31 +03:00
path_exists ( LVM_SHARED_PATH ) & &
! getenv ( " LVM_DID_EXEC " ) ) {
setenv ( " LVM_DID_EXEC " , base , 1 ) ;
execvp ( LVM_SHARED_PATH , argv ) ;
unsetenv ( " LVM_DID_EXEC " ) ;
}
2008-12-18 08:27:17 +03:00
if ( ! ( cmd = init_lvm ( ) ) )
2005-02-18 21:58:31 +03:00
return - 1 ;
cmd - > argv = argv ;
2006-08-19 01:17:18 +04:00
lvm_register_commands ( ) ;
2004-03-26 15:00:24 +03:00
2004-04-08 19:23:23 +04:00
if ( _lvm1_fallback ( cmd ) ) {
/* Attempt to run equivalent LVM1 tool instead */
if ( ! alias ) {
argv + + ;
argc - - ;
alias = 0 ;
}
if ( ! argc ) {
log_error ( " Falling back to LVM1 tools, but no "
" command specified. " ) ;
return ECMD_FAILED ;
}
2006-05-10 01:23:51 +04:00
_exec_lvm1_command ( argv ) ;
2004-04-08 19:23:23 +04:00
return ECMD_FAILED ;
}
2004-03-26 15:00:24 +03:00
# ifdef READLINE_SUPPORT
if ( ! alias & & argc = = 1 ) {
2008-01-09 18:55:44 +03:00
_nonroot_warning ( ) ;
2007-02-14 19:51:48 +03:00
ret = lvm_shell ( cmd , & _cmdline ) ;
2004-03-26 15:00:24 +03:00
goto out ;
}
# endif
if ( ! alias ) {
if ( argc < 2 ) {
log_fatal ( " Please supply an LVM command. " ) ;
_display_help ( ) ;
ret = EINVALID_CMD_LINE ;
goto out ;
}
argc - - ;
argv + + ;
}
2008-01-09 18:55:44 +03:00
_nonroot_warning ( ) ;
2006-08-19 01:17:18 +04:00
ret = lvm_run_command ( cmd , argc , argv ) ;
2004-03-26 15:00:24 +03:00
if ( ( ret = = ENO_SUCH_CMD ) & & ( ! alias ) )
ret = _run_script ( cmd , argc , argv ) ;
if ( ret = = ENO_SUCH_CMD )
log_error ( " No such command. Try 'help'. " ) ;
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 ) ;
}
2004-03-26 15:00:24 +03:00
out :
2006-08-19 01:17:18 +04:00
lvm_fin ( cmd ) ;
2010-01-11 22:19:17 +03:00
return lvm_return_code ( ret ) ;
2004-03-26 15:00:24 +03:00
}