2001-09-25 16:49:28 +04:00
/*
2001-12-20 14:52:54 +03:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-09-25 16:49:28 +04:00
*
2001-12-20 14:52:54 +03:00
* This file is released under the GPL .
2001-09-25 16:49:28 +04:00
*/
2001-10-06 01:39:30 +04:00
# include "tools.h"
2001-09-25 16:49:28 +04:00
2002-01-01 00:27:39 +03:00
# include <sys/stat.h>
2002-02-11 23:50:53 +03:00
int process_each_lv_in_vg ( struct cmd_context * cmd , struct volume_group * vg ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
struct logical_volume * lv ) )
2001-11-19 18:20:50 +03:00
{
int ret_max = 0 ;
int ret = 0 ;
struct list * lvh ;
struct logical_volume * lv ;
if ( vg - > status & EXPORTED_VG ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" is exported " , vg - > name ) ;
2001-11-19 18:20:50 +03:00
return ECMD_FAILED ;
}
2002-01-29 20:23:33 +03:00
2001-11-19 18:20:50 +03:00
list_iterate ( lvh , & vg - > lvs ) {
2002-01-21 19:49:32 +03:00
lv = list_item ( lvh , struct lv_list ) - > lv ;
2002-02-11 23:50:53 +03:00
ret = process_single ( cmd , lv ) ;
2001-11-19 18:20:50 +03:00
if ( ret > ret_max )
ret_max = ret ;
}
return ret_max ;
}
2002-02-11 23:50:53 +03:00
int process_each_lv ( struct cmd_context * cmd , int argc , char * * argv ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
struct logical_volume * lv ) )
2001-11-14 21:38:07 +03:00
{
int opt = 0 ;
int ret_max = 0 ;
int ret = 0 ;
int vg_count = 0 ;
struct list * vgh , * vgs ;
struct volume_group * vg ;
struct logical_volume * lv ;
2002-01-21 17:28:12 +03:00
struct lv_list * lvl ;
2001-11-14 21:38:07 +03:00
char * vg_name ;
if ( argc ) {
log_verbose ( " Using logical volume(s) on command line " ) ;
for ( ; opt < argc ; opt + + ) {
char * lv_name = argv [ opt ] ;
/* does VG exist? */
2002-02-11 23:50:53 +03:00
if ( ! ( vg_name = extract_vgname ( cmd - > fid , lv_name ) ) ) {
2001-11-14 21:38:07 +03:00
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2002-01-30 18:04:48 +03:00
log_verbose ( " Finding volume group \" %s \" " , vg_name ) ;
2002-02-11 23:50:53 +03:00
if ( ! ( vg = cmd - > fid - > ops - > vg_read ( cmd - > fid , vg_name ) ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" doesn't exist " ,
2001-11-14 21:38:07 +03:00
vg_name ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2002-01-29 20:23:33 +03:00
if ( vg - > status & EXPORTED_VG ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" is exported " ,
2002-01-29 20:23:33 +03:00
vg - > name ) ;
return ECMD_FAILED ;
}
2002-01-21 17:28:12 +03:00
if ( ! ( lvl = find_lv_in_vg ( vg , lv_name ) ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Can't find logical volume \" %s \" "
" in volume group \" %s \" " ,
2001-11-14 21:38:07 +03:00
lv_name , vg_name ) ;
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2002-01-21 19:49:32 +03:00
lv = lvl - > lv ;
2001-11-14 21:38:07 +03:00
2002-02-11 23:50:53 +03:00
if ( ( ret = process_single ( cmd , lv ) ) > ret_max )
2001-11-14 21:38:07 +03:00
ret_max = ret ;
}
} else {
2002-01-16 17:43:27 +03:00
log_verbose ( " Finding all logical volumes " ) ;
2002-02-11 23:50:53 +03:00
if ( ! ( vgs = cmd - > fid - > ops - > get_vgs ( cmd - > fid ) ) ) {
2001-11-14 21:38:07 +03:00
log_error ( " No volume groups found " ) ;
return ECMD_FAILED ;
}
list_iterate ( vgh , vgs ) {
vg_name = list_item ( vgh , struct name_list ) - > name ;
2002-02-11 23:50:53 +03:00
if ( ! ( vg = cmd - > fid - > ops - > vg_read ( cmd - > fid , vg_name ) ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" not found " ,
vg_name ) ;
2001-11-14 21:38:07 +03:00
if ( ret_max < ECMD_FAILED )
ret_max = ECMD_FAILED ;
continue ;
}
2002-02-11 23:50:53 +03:00
ret = process_each_lv_in_vg ( cmd , vg , process_single ) ;
2001-11-19 18:20:50 +03:00
if ( ret > ret_max )
ret_max = ret ;
2001-11-14 21:38:07 +03:00
vg_count + + ;
}
}
return ret_max ;
}
2002-02-12 00:00:35 +03:00
int process_each_vg ( struct cmd_context * cmd , int argc , char * * argv ,
int lock_type ,
int ( * process_single ) ( struct cmd_context * cmd ,
const char * vg_name ) )
2001-10-06 01:39:30 +04:00
{
int opt = 0 ;
int ret_max = 0 ;
int ret = 0 ;
2001-10-31 15:47:01 +03:00
struct list * vgh ;
2001-11-14 21:38:07 +03:00
struct list * vgs ;
2001-10-06 01:39:30 +04:00
2002-02-11 18:42:34 +03:00
char * vg_name ;
2001-10-06 01:39:30 +04:00
if ( argc ) {
log_verbose ( " Using volume group(s) on command line " ) ;
2002-02-11 18:42:34 +03:00
for ( ; opt < argc ; opt + + ) {
vg_name = argv [ opt ] ;
2002-03-15 19:07:38 +03:00
if ( ! lock_vol ( cmd , vg_name , lock_type ) ) {
2002-02-11 18:42:34 +03:00
log_error ( " Can't lock %s: skipping " , vg_name ) ;
continue ;
}
2002-02-11 23:50:53 +03:00
if ( ( ret = process_single ( cmd , vg_name ) ) > ret_max )
2001-10-06 01:39:30 +04:00
ret_max = ret ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name ) ;
2002-02-11 18:42:34 +03:00
}
2001-10-06 01:39:30 +04:00
} else {
2002-01-16 17:43:27 +03:00
log_verbose ( " Finding all volume groups " ) ;
2002-02-11 23:50:53 +03:00
if ( ! ( vgs = cmd - > fid - > ops - > get_vgs ( cmd - > fid ) ) ) {
2001-10-06 01:39:30 +04:00
log_error ( " No volume groups found " ) ;
return ECMD_FAILED ;
}
2001-11-14 21:38:07 +03:00
list_iterate ( vgh , vgs ) {
2002-02-12 00:00:35 +03:00
vg_name = list_item ( vgh , struct name_list ) - > name ;
2002-03-15 19:07:38 +03:00
if ( ! lock_vol ( cmd , vg_name , lock_type ) ) {
2002-02-11 18:42:34 +03:00
log_error ( " Can't lock %s: skipping " , vg_name ) ;
continue ;
}
2002-02-11 23:50:53 +03:00
ret = process_single ( cmd , vg_name ) ;
2002-02-12 00:00:35 +03:00
2001-10-06 01:39:30 +04:00
if ( ret > ret_max )
ret_max = ret ;
2002-03-11 18:08:39 +03:00
unlock_vg ( cmd , vg_name ) ;
2001-10-06 01:39:30 +04:00
}
}
return ret_max ;
}
2001-10-08 22:44:22 +04:00
2002-02-11 23:50:53 +03:00
int process_each_pv_in_vg ( struct cmd_context * cmd , struct volume_group * vg ,
2002-02-12 00:00:35 +03:00
int ( * process_single ) ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct physical_volume * pv ) )
2001-11-19 18:20:50 +03:00
{
int ret_max = 0 ;
int ret = 0 ;
struct list * pvh ;
2002-01-21 19:05:23 +03:00
struct physical_volume * pv ;
2001-11-19 18:20:50 +03:00
2002-01-21 19:05:23 +03:00
list_iterate ( pvh , & vg - > pvs ) {
pv = list_item ( pvh , struct pv_list ) - > pv ;
2001-11-19 18:20:50 +03:00
2002-02-11 23:50:53 +03:00
if ( ( ret = process_single ( cmd , vg , pv ) ) > ret_max )
2002-01-21 19:05:23 +03:00
ret_max = ret ;
}
return ret_max ;
2001-11-19 18:20:50 +03:00
}
2002-02-12 00:00:35 +03:00
int process_each_pv ( struct cmd_context * cmd , int argc , char * * argv ,
struct volume_group * vg ,
int ( * process_single ) ( struct cmd_context * cmd ,
struct volume_group * vg ,
struct physical_volume * pv ) )
2001-10-12 01:35:55 +04:00
{
int opt = 0 ;
int ret_max = 0 ;
int ret = 0 ;
2002-01-21 17:28:12 +03:00
struct pv_list * pvl ;
2001-10-12 01:35:55 +04:00
if ( argc ) {
log_verbose ( " Using physical volume(s) on command line " ) ;
for ( ; opt < argc ; opt + + ) {
2002-01-21 17:28:12 +03:00
if ( ! ( pvl = find_pv_in_vg ( vg , argv [ opt ] ) ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Physical Volume \" %s \" not found in "
" Volume Group \" %s \" " , argv [ opt ] ,
2001-10-12 01:35:55 +04:00
vg - > name ) ;
continue ;
}
2002-02-11 23:50:53 +03:00
ret = process_single ( cmd , vg , pvl - > pv ) ;
2001-10-12 01:35:55 +04:00
if ( ret > ret_max )
ret_max = ret ;
}
} else {
log_verbose ( " Using all physical volume(s) in volume group " ) ;
2002-02-11 23:50:53 +03:00
process_each_pv_in_vg ( cmd , vg , process_single ) ;
2001-10-12 01:35:55 +04:00
}
return ret_max ;
}
2001-10-08 22:44:22 +04:00
int is_valid_chars ( char * n )
{
register char c ;
2002-03-19 19:41:44 +03:00
/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
if ( * n = = ' - ' )
return 0 ;
2001-10-08 22:44:22 +04:00
while ( ( c = * n + + ) )
2001-10-12 01:35:55 +04:00
if ( ! isalnum ( c ) & & c ! = ' . ' & & c ! = ' _ ' & & c ! = ' - ' & & c ! = ' + ' )
2001-10-08 22:44:22 +04:00
return 0 ;
return 1 ;
}
2001-11-12 18:10:01 +03:00
char * extract_vgname ( struct format_instance * fi , char * lv_name )
2001-11-14 21:38:07 +03:00
{
2001-10-29 16:52:23 +03:00
char * vg_name = lv_name ;
2001-11-06 22:02:26 +03:00
char * st ;
2001-11-12 18:10:01 +03:00
char * dev_dir = fi - > cmd - > dev_dir ;
2001-10-29 16:52:23 +03:00
/* Path supplied? */
2001-11-06 22:02:26 +03:00
if ( vg_name & & strchr ( vg_name , ' / ' ) ) {
2001-11-15 20:27:45 +03:00
/* Strip dev_dir (optional) */
2001-11-12 18:10:01 +03:00
if ( ! strncmp ( vg_name , dev_dir , strlen ( dev_dir ) ) )
vg_name + = strlen ( dev_dir ) ;
2001-10-29 16:52:23 +03:00
/* Require exactly one slash */
2001-10-29 21:23:35 +03:00
/* FIXME But allow for consecutive slashes */
2001-10-29 16:52:23 +03:00
if ( ! ( st = strchr ( vg_name , ' / ' ) ) | | ( strchr ( st + 1 , ' / ' ) ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " \" %s \" : Invalid path for Logical Volume " ,
2001-11-14 21:38:07 +03:00
lv_name ) ;
2001-10-29 16:52:23 +03:00
return 0 ;
}
2002-02-11 23:50:53 +03:00
vg_name = pool_strdup ( fi - > cmd - > mem , vg_name ) ;
2001-10-29 16:52:23 +03:00
if ( ! vg_name ) {
log_error ( " Allocation of vg_name failed " ) ;
return 0 ;
}
* strchr ( vg_name , ' / ' ) = ' \0 ' ;
return vg_name ;
}
2001-11-06 22:02:26 +03:00
2002-02-11 23:50:53 +03:00
if ( ! ( vg_name = default_vgname ( fi ) ) ) {
2001-11-06 22:02:26 +03:00
if ( lv_name )
2002-01-30 18:04:48 +03:00
log_error ( " Path required for Logical Volume \" %s \" " ,
2001-11-14 21:38:07 +03:00
lv_name ) ;
2001-11-06 22:02:26 +03:00
return 0 ;
}
2001-11-14 21:38:07 +03:00
2001-11-06 22:02:26 +03:00
return vg_name ;
}
2001-11-12 18:10:01 +03:00
char * default_vgname ( struct format_instance * fi )
2001-11-06 22:02:26 +03:00
{
char * vg_path ;
2001-11-12 18:10:01 +03:00
char * dev_dir = fi - > cmd - > dev_dir ;
2001-11-06 22:02:26 +03:00
2001-10-29 16:52:23 +03:00
/* Take default VG from environment? */
2001-11-14 21:38:07 +03:00
vg_path = getenv ( " LVM_VG_NAME " ) ;
2001-11-06 22:02:26 +03:00
if ( ! vg_path )
2001-10-29 16:52:23 +03:00
return 0 ;
2001-11-15 20:27:45 +03:00
/* Strip dev_dir (optional) */
2001-11-12 18:10:01 +03:00
if ( ! strncmp ( vg_path , dev_dir , strlen ( dev_dir ) ) )
vg_path + = strlen ( dev_dir ) ;
2001-10-29 16:52:23 +03:00
if ( strchr ( vg_path , ' / ' ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Environment Volume Group in LVM_VG_NAME invalid: "
" \" %s \" " , vg_path ) ;
2001-10-29 16:52:23 +03:00
return 0 ;
}
2002-02-11 23:50:53 +03:00
return pool_strdup ( fi - > cmd - > mem , vg_path ) ;
2001-10-29 16:52:23 +03:00
}
2002-01-21 19:05:23 +03:00
struct list * create_pv_list ( struct pool * mem ,
2002-01-29 20:23:33 +03:00
struct volume_group * vg , int argc , char * * argv )
2002-01-21 19:05:23 +03:00
{
struct list * r ;
struct pv_list * pvl , * new_pvl ;
int i ;
/* Build up list of PVs */
if ( ! ( r = pool_alloc ( mem , sizeof ( * r ) ) ) ) {
log_error ( " Allocation of list failed " ) ;
return NULL ;
}
list_init ( r ) ;
for ( i = 0 ; i < argc ; i + + ) {
if ( ! ( pvl = find_pv_in_vg ( vg , argv [ i ] ) ) ) {
2002-01-30 18:04:48 +03:00
log_err ( " Physical Volume \" %s \" not found in "
" Volume Group \" %s \" " , argv [ i ] , vg - > name ) ;
2002-01-21 19:05:23 +03:00
return NULL ;
}
if ( pvl - > pv - > pe_count = = pvl - > pv - > pe_allocated ) {
2002-01-30 18:04:48 +03:00
log_err ( " No free extents on physical volume \" %s \" " ,
2002-01-21 19:05:23 +03:00
argv [ i ] ) ;
continue ;
}
if ( ! ( new_pvl = pool_alloc ( mem , sizeof ( * new_pvl ) ) ) ) {
log_err ( " Unable to allocate physical volume list. " ) ;
return NULL ;
}
memcpy ( new_pvl , pvl , sizeof ( * new_pvl ) ) ;
list_add ( r , & new_pvl - > list ) ;
}
2002-01-29 20:23:33 +03:00
return list_empty ( r ) ? NULL : r ;
2002-01-21 19:05:23 +03:00
}