2001-11-21 12:20:05 +03:00
/*
2002-02-22 14:44:56 +03:00
* Copyright ( C ) 2001 - 2002 Sistina Software ( UK ) Limited .
2001-11-21 12:20:05 +03:00
*
* This file is released under the LGPL .
*/
# include "format-text.h"
2002-01-07 12:16:20 +03:00
# include "import-export.h"
2001-11-21 12:20:05 +03:00
2002-01-09 22:16:48 +03:00
# include "lvm-file.h"
2001-11-21 12:20:05 +03:00
# include "log.h"
# include "pool.h"
# include "config.h"
# include "hash.h"
2002-02-22 14:44:56 +03:00
# include "display.h"
2002-01-10 19:48:28 +03:00
# include "dbg_malloc.h"
2002-02-11 23:50:53 +03:00
# include "toolcontext.h"
2001-11-21 12:20:05 +03:00
2002-01-09 22:16:48 +03:00
# include <unistd.h>
# include <sys/types.h>
# include <sys/file.h>
# include <limits.h>
2002-02-22 14:44:56 +03:00
/* Arbitrary limits copied from format1/disk_rep.h */
# define MAX_PV 256
# define MAX_LV 256
# define MAX_VG 99
2002-02-25 01:31:55 +03:00
# define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
2002-02-22 14:44:56 +03:00
2001-11-21 12:20:05 +03:00
/*
2002-01-07 12:05:31 +03:00
* NOTE : Currently there can be only one vg per file .
2001-11-21 12:20:05 +03:00
*/
2002-01-15 20:37:23 +03:00
struct text_c {
char * path ;
2002-02-08 14:13:47 +03:00
char * desc ;
2002-01-15 20:37:23 +03:00
struct uuid_map * um ;
} ;
2002-02-22 14:44:56 +03:00
static int _pv_setup ( struct format_instance * fi , struct physical_volume * pv ,
struct volume_group * vg )
2001-11-21 12:20:05 +03:00
{
2002-02-22 14:44:56 +03:00
/* setup operations for the PV structure */
if ( pv - > size > MAX_PV_SIZE )
pv - > size - - ;
if ( pv - > size > MAX_PV_SIZE ) {
/* FIXME Limit hardcoded */
log_error ( " Physical volumes cannot be bigger than 2TB " ) ;
return 0 ;
}
2001-11-21 12:20:05 +03:00
2002-02-22 14:44:56 +03:00
return 1 ;
2001-11-21 12:20:05 +03:00
}
2002-02-22 14:44:56 +03:00
static int _vg_setup ( struct format_instance * fi , struct volume_group * vg )
2001-11-21 12:20:05 +03:00
{
2002-02-22 14:44:56 +03:00
/* just check max_pv and max_lv */
if ( vg - > max_lv > = MAX_LV )
vg - > max_lv = MAX_LV - 1 ;
2001-11-21 12:20:05 +03:00
2002-02-25 01:31:55 +03:00
if ( vg - > max_pv > = MAX_PV )
2002-02-22 14:44:56 +03:00
vg - > max_pv = MAX_PV - 1 ;
2001-11-21 12:20:05 +03:00
2002-02-22 14:44:56 +03:00
return 1 ;
2001-11-21 12:20:05 +03:00
}
2002-02-22 14:44:56 +03:00
static int _lv_setup ( struct format_instance * fi , struct logical_volume * lv )
2001-11-21 12:20:05 +03:00
{
2002-02-22 14:44:56 +03:00
uint64_t max_size = UINT_MAX ;
2001-11-21 12:20:05 +03:00
2002-02-22 14:44:56 +03:00
if ( lv - > size > max_size ) {
2002-02-25 01:31:55 +03:00
char * dummy = display_size ( max_size , SIZE_SHORT ) ;
2002-02-22 14:44:56 +03:00
log_error ( " logical volumes cannot be larger than %s " , dummy ) ;
dbg_free ( dummy ) ;
return 0 ;
}
return 1 ;
2001-11-21 12:20:05 +03:00
}
2002-01-07 14:12:11 +03:00
static struct volume_group * _vg_read ( struct format_instance * fi ,
const char * vg_name )
2001-11-21 12:20:05 +03:00
{
2002-01-15 20:37:23 +03:00
struct text_c * tc = ( struct text_c * ) fi - > private ;
2002-01-10 17:27:47 +03:00
struct volume_group * vg ;
2002-02-11 14:43:17 +03:00
time_t when ;
char * desc ;
2002-01-10 17:27:47 +03:00
2002-02-11 14:43:17 +03:00
if ( ! ( vg = text_vg_import ( fi - > cmd , tc - > path , tc - > um , & when , & desc ) ) ) {
2002-01-10 17:27:47 +03:00
stack ;
return NULL ;
}
/*
* Currently you can only have a single volume group per
* text file ( this restriction may remain ) . We need to
* check that it contains the correct volume group .
*/
if ( strcmp ( vg_name , vg - > name ) ) {
pool_free ( fi - > cmd - > mem , vg ) ;
log_err ( " '%s' does not contain volume group '%s'. " ,
2002-01-15 20:37:23 +03:00
tc - > path , vg_name ) ;
2002-01-10 17:27:47 +03:00
return NULL ;
}
return vg ;
2001-11-21 12:20:05 +03:00
}
2002-01-07 14:12:11 +03:00
static int _vg_write ( struct format_instance * fi , struct volume_group * vg )
2001-11-21 12:20:05 +03:00
{
2002-01-15 20:37:23 +03:00
struct text_c * tc = ( struct text_c * ) fi - > private ;
2002-01-07 12:05:31 +03:00
FILE * fp ;
2002-01-10 17:27:47 +03:00
int fd ;
2002-01-09 22:16:48 +03:00
char * slash ;
char temp_file [ PATH_MAX ] , temp_dir [ PATH_MAX ] ;
2002-01-15 20:37:23 +03:00
slash = rindex ( tc - > path , ' / ' ) ;
2001-11-21 12:20:05 +03:00
2002-01-09 22:16:48 +03:00
if ( slash = = 0 )
strcpy ( temp_dir , " . " ) ;
2002-01-15 20:37:23 +03:00
else if ( slash - tc - > path < PATH_MAX ) {
strncpy ( temp_dir , tc - > path , slash - tc - > path ) ;
temp_dir [ slash - tc - > path ] = ' \0 ' ;
2002-01-10 17:27:47 +03:00
2002-01-09 22:16:48 +03:00
} else {
log_error ( " Text format failed to determine directory. " ) ;
return 0 ;
}
2002-02-25 01:31:55 +03:00
if ( ! create_temp_name ( temp_dir , temp_file , sizeof ( temp_file ) , & fd ) ) {
log_err ( " Couldn't create temporary text file name. " ) ;
return 0 ;
}
2002-01-09 22:16:48 +03:00
if ( ! ( fp = fdopen ( fd , " w " ) ) ) {
log_sys_error ( " fdopen " , temp_file ) ;
close ( fd ) ;
2002-01-07 12:05:31 +03:00
return 0 ;
}
2001-11-21 12:20:05 +03:00
2002-02-08 14:13:47 +03:00
if ( ! text_vg_export ( fp , vg , tc - > desc ) ) {
2002-01-09 22:16:48 +03:00
log_error ( " Failed to write metadata to %s. " , temp_file ) ;
2002-01-09 16:07:03 +03:00
fclose ( fp ) ;
return 0 ;
}
2002-01-09 22:16:48 +03:00
if ( fclose ( fp ) ) {
2002-01-15 20:37:23 +03:00
log_sys_error ( " fclose " , tc - > path ) ;
2002-01-07 12:05:31 +03:00
return 0 ;
}
2001-11-21 12:20:05 +03:00
2002-01-15 20:37:23 +03:00
if ( rename ( temp_file , tc - > path ) ) {
log_error ( " %s: rename to %s failed: %s " , temp_file , tc - > path ,
2002-01-09 22:16:48 +03:00
strerror ( errno ) ) ;
return 0 ;
}
2002-01-07 12:05:31 +03:00
return 1 ;
2001-11-21 12:20:05 +03:00
}
2002-02-22 14:44:56 +03:00
static struct list * _get_vgs ( struct format_instance * fi )
{
2002-02-25 01:31:55 +03:00
struct text_c * tc = ( struct text_c * ) fi - > private ;
2002-02-22 14:44:56 +03:00
struct list * names = pool_alloc ( fi - > cmd - > mem , sizeof ( * names ) ) ;
struct name_list * nl ;
struct volume_group * vg ;
char * slash ;
char * vgname ;
if ( ! names ) {
stack ;
return NULL ;
}
list_init ( names ) ;
/* Determine the VG name from the file name */
slash = rindex ( tc - > path , ' / ' ) ;
if ( slash ) {
2002-02-25 01:31:55 +03:00
vgname = pool_alloc ( fi - > cmd - > mem , strlen ( slash ) ) ;
strcpy ( vgname , slash + 1 ) ;
} else {
vgname = pool_alloc ( fi - > cmd - > mem , strlen ( tc - > path ) + 1 ) ;
strcpy ( vgname , tc - > path ) ;
2002-02-22 14:44:56 +03:00
}
vg = _vg_read ( fi , vgname ) ;
if ( vg ) {
2002-02-25 01:31:55 +03:00
pool_free ( fi - > cmd - > mem , vg ) ;
if ( ! ( nl = pool_alloc ( fi - > cmd - > mem , sizeof ( * nl ) ) ) ) {
stack ;
goto bad ;
}
nl - > name = vgname ;
2002-02-22 14:44:56 +03:00
2002-02-25 01:31:55 +03:00
list_add ( names , & nl - > list ) ;
2002-02-22 14:44:56 +03:00
}
return names ;
2002-02-25 01:31:55 +03:00
bad :
2002-02-22 14:44:56 +03:00
pool_free ( fi - > cmd - > mem , names ) ;
return NULL ;
}
static struct list * _get_pvs ( struct format_instance * fi )
{
2002-02-25 01:31:55 +03:00
struct pv_list * pvl ;
2002-02-22 14:44:56 +03:00
struct list * vgh ;
struct list * pvh ;
struct list * results = pool_alloc ( fi - > cmd - > mem , sizeof ( * results ) ) ;
2002-02-25 01:31:55 +03:00
struct list * vgs = _get_vgs ( fi ) ;
2002-02-22 14:44:56 +03:00
list_init ( results ) ;
list_iterate ( vgh , vgs ) {
2002-02-25 01:31:55 +03:00
struct volume_group * vg ;
struct name_list * nl ;
nl = list_item ( vgh , struct name_list ) ;
vg = _vg_read ( fi , nl - > name ) ;
if ( vg ) {
list_iterate ( pvh , & vg - > pvs ) {
struct pv_list * vgpv =
list_item ( pvh , struct pv_list ) ;
pvl = pool_alloc ( fi - > cmd - > mem , sizeof ( * pvl ) ) ;
if ( ! pvl ) {
stack ;
goto bad ;
}
/* ?? do we need to clone the pv structure...really? Nah. */
pvl - > pv = vgpv - > pv ;
list_add ( results , & pvl - > list ) ;
}
2002-02-22 14:44:56 +03:00
}
}
return results ;
2002-02-25 01:31:55 +03:00
bad :
2002-02-22 14:44:56 +03:00
pool_free ( fi - > cmd - > mem , vgs ) ;
2002-02-25 01:31:55 +03:00
return NULL ;
2002-02-22 14:44:56 +03:00
}
static int _pv_write ( struct format_instance * fi , struct physical_volume * pv )
{
2002-02-25 01:31:55 +03:00
struct volume_group * vg ;
2002-02-22 14:44:56 +03:00
struct list * pvh ;
vg = _vg_read ( fi , pv - > vg_name ) ;
/* Find the PV in this VG */
if ( vg ) {
2002-02-25 01:31:55 +03:00
list_iterate ( pvh , & vg - > pvs ) {
struct pv_list * vgpv = list_item ( pvh , struct pv_list ) ;
if ( id_equal ( & pv - > id , & vgpv - > pv - > id ) ) {
vgpv - > pv - > status = pv - > status ;
vgpv - > pv - > size = pv - > size ;
/* Not sure if it's worth doing these */
vgpv - > pv - > pe_size = pv - > pe_size ;
vgpv - > pv - > pe_count = pv - > pe_count ;
vgpv - > pv - > pe_start = pv - > pe_start ;
vgpv - > pv - > pe_allocated = pv - > pe_allocated ;
/* Write it back */
_vg_write ( fi , vg ) ;
pool_free ( fi - > cmd - > mem , vg ) ;
return 1 ;
}
2002-02-22 14:44:56 +03:00
}
2002-02-25 01:31:55 +03:00
pool_free ( fi - > cmd - > mem , vg ) ;
2002-02-22 14:44:56 +03:00
}
/* Can't handle PVs not in a VG */
return 0 ;
}
static struct physical_volume * _pv_read ( struct format_instance * fi ,
const char * pv_name )
{
2002-02-25 01:31:55 +03:00
struct list * vgs = _get_vgs ( fi ) ;
2002-02-22 14:44:56 +03:00
struct list * vgh ;
struct list * pvh ;
struct physical_volume * pv ;
/* Look for the PV */
list_iterate ( vgh , vgs ) {
2002-02-25 01:31:55 +03:00
struct volume_group * vg ;
struct name_list * nl ;
nl = list_item ( vgh , struct name_list ) ;
vg = _vg_read ( fi , nl - > name ) ;
if ( vg ) {
list_iterate ( pvh , & vg - > pvs ) {
struct pv_list * vgpv =
list_item ( pvh , struct pv_list ) ;
if ( ! strcmp ( dev_name ( vgpv - > pv - > dev ) , pv_name ) ) {
pv = pool_alloc ( fi - > cmd - > mem ,
sizeof ( * pv ) ) ;
if ( ! pv ) {
stack ;
pool_free ( fi - > cmd - > mem , vg ) ;
return NULL ;
}
/* Memberwise copy */
* pv = * vgpv - > pv ;
pv - > vg_name =
pool_alloc ( fi - > cmd - > mem ,
strlen ( vgpv - > pv - >
vg_name ) + 1 ) ;
if ( ! pv - > vg_name ) {
stack ;
pool_free ( fi - > cmd - > mem , vg ) ;
return NULL ;
}
strcpy ( pv - > vg_name , vgpv - > pv - > vg_name ) ;
pool_free ( fi - > cmd - > mem , vg ) ;
return pv ;
}
2002-02-22 14:44:56 +03:00
}
pool_free ( fi - > cmd - > mem , vg ) ;
}
}
2002-02-25 01:31:55 +03:00
return NULL ;
2002-02-22 14:44:56 +03:00
}
2002-01-07 14:12:11 +03:00
static void _destroy ( struct format_instance * fi )
2001-11-21 12:20:05 +03:00
{
2002-01-15 20:37:23 +03:00
struct text_c * tc = ( struct text_c * ) fi - > private ;
dbg_free ( tc - > path ) ;
2002-02-11 21:21:54 +03:00
dbg_free ( tc - > desc ) ;
2002-01-15 20:37:23 +03:00
dbg_free ( tc ) ;
2002-01-10 17:27:47 +03:00
dbg_free ( fi ) ;
2001-11-21 12:20:05 +03:00
}
static struct format_handler _text_handler = {
2002-02-25 01:31:55 +03:00
get_vgs : _get_vgs ,
get_pvs : _get_pvs ,
pv_read : _pv_read ,
pv_setup : _pv_setup ,
pv_write : _pv_write ,
vg_setup : _vg_setup ,
lv_setup : _lv_setup ,
vg_read : _vg_read ,
vg_write : _vg_write ,
destroy : _destroy
2001-11-21 12:20:05 +03:00
} ;
2002-01-07 12:05:31 +03:00
struct format_instance * text_format_create ( struct cmd_context * cmd ,
2002-01-15 20:37:23 +03:00
const char * file ,
2002-02-08 14:13:47 +03:00
struct uuid_map * um ,
const char * desc )
2001-11-21 12:20:05 +03:00
{
struct format_instance * fi ;
2002-02-08 14:13:47 +03:00
char * path , * d ;
2002-01-15 20:37:23 +03:00
struct text_c * tc ;
2001-11-21 12:20:05 +03:00
2002-01-10 17:27:47 +03:00
if ( ! ( fi = dbg_malloc ( sizeof ( * fi ) ) ) ) {
2002-02-08 14:13:47 +03:00
stack ;
goto no_mem ;
2001-11-21 12:20:05 +03:00
}
2002-01-10 17:27:47 +03:00
if ( ! ( path = dbg_strdup ( file ) ) ) {
2002-02-08 14:13:47 +03:00
stack ;
goto no_mem ;
}
if ( ! ( d = dbg_strdup ( desc ) ) ) {
stack ;
goto no_mem ;
2001-11-21 12:20:05 +03:00
}
2002-01-15 20:37:23 +03:00
if ( ! ( tc = dbg_malloc ( sizeof ( * tc ) ) ) ) {
2002-02-08 14:13:47 +03:00
stack ;
goto no_mem ;
2002-01-15 20:37:23 +03:00
}
tc - > path = path ;
2002-02-08 14:13:47 +03:00
tc - > desc = d ;
2002-01-15 20:37:23 +03:00
tc - > um = um ;
2001-11-21 12:20:05 +03:00
fi - > cmd = cmd ;
2002-01-07 12:16:20 +03:00
fi - > ops = & _text_handler ;
2002-01-15 20:37:23 +03:00
fi - > private = tc ;
2001-11-21 12:20:05 +03:00
return fi ;
2002-02-08 14:13:47 +03:00
2002-02-25 01:31:55 +03:00
no_mem :
2002-02-08 14:13:47 +03:00
if ( fi )
dbg_free ( fi ) ;
if ( path )
dbg_free ( path ) ;
if ( d )
dbg_free ( path ) ;
log_err ( " Couldn't allocate text format object. " ) ;
return NULL ;
2001-11-21 12:20:05 +03:00
}