2001-12-11 15:16:58 +03:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*/
2001-12-11 15:18:56 +03:00
# include "import-export.h"
2001-12-11 15:16:58 +03:00
# include "metadata.h"
# include "log.h"
# include "hash.h"
# include "pool.h"
2001-12-20 14:52:54 +03:00
# include "dbg_malloc.h"
2001-12-20 19:05:14 +03:00
# include "lvm-string.h"
2001-12-11 15:16:58 +03:00
# include <stdio.h>
2001-12-20 14:52:54 +03:00
# include <stdarg.h>
# include <time.h>
2001-12-11 15:16:58 +03:00
/*
* The first half of this file deals with
* exporting the vg , ie . writing it to a file .
*/
struct formatter {
struct pool * mem ; /* pv names allocated from here */
struct hash_table * pv_names ; /* dev_name -> pv_name (eg, pv1) */
FILE * fp ; /* where we're writing to */
int indent ; /* current level of indentation */
2001-12-20 19:05:14 +03:00
int error ;
2001-12-11 15:16:58 +03:00
} ;
2001-12-20 19:05:14 +03:00
/*
* Formatting functions .
*/
static void _out_size ( struct formatter * f , uint64_t size ,
const char * fmt , . . . )
__attribute__ ( ( format ( printf , 3 , 4 ) ) ) ;
static void _out_hint ( struct formatter * f , const char * fmt , . . . )
__attribute__ ( ( format ( printf , 2 , 3 ) ) ) ;
static void _out ( struct formatter * f , const char * fmt , . . . )
__attribute__ ( ( format ( printf , 2 , 3 ) ) ) ;
2001-12-11 15:16:58 +03:00
# define MAX_INDENT 5
static void _inc_indent ( struct formatter * f )
{
if ( + + f - > indent > MAX_INDENT )
f - > indent = MAX_INDENT ;
}
static void _dec_indent ( struct formatter * f )
{
2001-12-20 19:05:14 +03:00
if ( ! f - > indent - - ) {
2001-12-11 15:16:58 +03:00
log_debug ( " Indenting seems to have messed up \n " ) ;
f - > indent = 0 ;
}
}
/*
* Newline function for prettier layout .
*/
static void _nl ( struct formatter * f )
{
fprintf ( f - > fp , " \n " ) ;
}
# define COMMENT_TAB 6
static void _out_with_comment ( struct formatter * f , const char * comment ,
const char * fmt , va_list ap )
{
int i ;
char white_space [ MAX_INDENT + 1 ] ;
2001-12-20 19:05:14 +03:00
if ( ferror ( f - > fp ) )
return ;
2001-12-11 15:16:58 +03:00
for ( i = 0 ; i < f - > indent ; i + + )
white_space [ i ] = ' \t ' ;
white_space [ i ] = ' \0 ' ;
fprintf ( f - > fp , white_space ) ;
i = vfprintf ( f - > fp , fmt , ap ) ;
if ( comment ) {
/*
* line comments up if possible .
*/
i + = 8 * f - > indent ;
i / = 8 ;
i + + ;
do
fputc ( ' \t ' , f - > fp ) ;
while ( + + i < COMMENT_TAB ) ;
fprintf ( f - > fp , comment ) ;
}
fputc ( ' \n ' , f - > fp ) ;
}
/*
* Formats a string , converting a size specified
* in 512 - byte sectors to a more human readable
* form ( eg , megabytes ) . We may want to lift this
* for other code to use .
*/
static int _sectors_to_units ( uint64_t sectors , char * buffer , size_t s )
{
2001-12-20 14:52:54 +03:00
static char * _units [ ] = {
2001-12-11 15:16:58 +03:00
" Kilobytes " ,
" Megabytes " ,
" Gigabytes " ,
" Terrabytes " ,
NULL
2001-12-20 14:52:54 +03:00
} ;
2001-12-11 15:16:58 +03:00
int i ;
double d = ( double ) sectors ;
/* to convert to K */
d / = 2.0 ;
for ( i = 0 ; ( d > 1024.0 ) & & _units [ i ] ; i + + )
d / = 1024.0 ;
/* FIXME: arrange so this doesn't print a
* decimal point unless we have a
* fractional part . */
2001-12-31 22:09:51 +03:00
return lvm_snprintf ( buffer , s , " # %g %s " , d , _units [ i ] ) > 0 ;
2001-12-11 15:16:58 +03:00
}
/*
* Appends a comment giving a size in more easily
* readable form ( eg , 4 M instead of 8096 ) .
*/
static void _out_size ( struct formatter * f , uint64_t size ,
const char * fmt , . . . )
{
char buffer [ 64 ] ;
va_list ap ;
_sectors_to_units ( size , buffer , sizeof ( buffer ) ) ;
va_start ( ap , fmt ) ;
_out_with_comment ( f , buffer , fmt , ap ) ;
va_end ( ap ) ;
}
/*
* Appends a comment indicating that the line is
* only a hint .
*/
static void _out_hint ( struct formatter * f , const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
_out_with_comment ( f , " # Hint only " , fmt , ap ) ;
va_end ( ap ) ;
}
/*
* The normal output function .
*/
static void _out ( struct formatter * f , const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
_out_with_comment ( f , NULL , fmt , ap ) ;
va_end ( ap ) ;
}
static int _print_header ( struct formatter * f , struct volume_group * vg )
{
2001-12-20 14:52:54 +03:00
time_t t ;
t = time ( NULL ) ;
2001-12-11 15:16:58 +03:00
_out ( f ,
" # This file was originally generated by the LVM2 library \n "
" # It is inadvisable for people to edit this by hand unless \n "
2001-12-20 19:05:14 +03:00
" # they know what they're doing. \n "
2001-12-20 14:52:54 +03:00
" # Generated: %s \n " , ctime ( & t ) ) ;
2001-12-11 15:16:58 +03:00
return 1 ;
}
static int _print_vg ( struct formatter * f , struct volume_group * vg )
{
char buffer [ 256 ] ;
2001-12-20 14:52:54 +03:00
if ( ! id_write_format ( & vg - > id , buffer , sizeof ( buffer ) ) ) {
2001-12-11 15:16:58 +03:00
stack ;
return 0 ;
}
_out ( f , " id = \" %s \" " , buffer ) ;
2001-12-20 14:52:54 +03:00
if ( ! print_flags ( vg - > status , VG_FLAGS , buffer , sizeof ( buffer ) ) ) {
2001-12-11 15:16:58 +03:00
stack ;
return 0 ;
}
2001-12-20 19:05:14 +03:00
_out ( f , " status = %s " , buffer ) ;
2001-12-11 15:16:58 +03:00
_out_size ( f , vg - > extent_size , " extent_size = %u " , vg - > extent_size ) ;
_out ( f , " max_lv = %u " , vg - > max_lv ) ;
_out ( f , " max_pv = %u " , vg - > max_pv ) ;
return 1 ;
}
/*
* Get the pv % d name from the formatters hash
* table .
*/
static inline const char *
_get_pv_name ( struct formatter * f , struct physical_volume * pv )
{
2001-12-20 14:52:54 +03:00
return ( const char * ) hash_lookup ( f - > pv_names , dev_name ( pv - > dev ) ) ;
2001-12-11 15:16:58 +03:00
}
static int _print_pvs ( struct formatter * f , struct volume_group * vg )
{
2001-12-20 14:52:54 +03:00
struct list * pvh ;
2001-12-11 15:16:58 +03:00
struct physical_volume * pv ;
char buffer [ 256 ] ;
const char * name ;
_out ( f , " physical_volumes { " ) ;
_nl ( f ) ;
_inc_indent ( f ) ;
list_iterate ( pvh , & vg - > pvs ) {
2001-12-20 19:05:14 +03:00
pv = & ( list_item ( pvh , struct pv_list ) - > pv ) ;
2001-12-11 15:16:58 +03:00
if ( ! ( name = _get_pv_name ( f , pv ) ) ) {
stack ;
return 0 ;
}
_out ( f , " %s { " , name ) ;
_inc_indent ( f ) ;
pv = & list_item ( pvh , struct pv_list ) - > pv ;
2001-12-20 14:52:54 +03:00
if ( ! id_write_format ( & pv - > id , buffer , sizeof ( buffer ) ) ) {
2001-12-11 15:16:58 +03:00
stack ;
return 0 ;
}
2001-12-20 19:05:14 +03:00
_out ( f , " id = \" %s \" " , buffer ) ;
2001-12-11 15:16:58 +03:00
_out_hint ( f , " device = %s " , dev_name ( pv - > dev ) ) ;
_nl ( f ) ;
2001-12-20 14:52:54 +03:00
if ( ! print_flags ( pv - > status , PV_FLAGS ,
2001-12-11 15:16:58 +03:00
buffer , sizeof ( buffer ) ) ) {
stack ;
return 0 ;
}
_out ( f , " status = %s " , buffer ) ;
2001-12-20 19:05:14 +03:00
_out ( f , " pe_start = %llu " , pv - > pe_start ) ;
2001-12-11 15:16:58 +03:00
_out_size ( f , vg - > extent_size * ( uint64_t ) pv - > pe_count ,
" pe_count = %u " , pv - > pe_count ) ;
_dec_indent ( f ) ;
_out ( f , " } " ) ;
_nl ( f ) ;
}
_dec_indent ( f ) ;
_out ( f , " } " ) ;
return 1 ;
}
static int _print_segment ( struct formatter * f , struct volume_group * vg ,
int count , struct stripe_segment * seg , int last )
{
int s ;
const char * name ;
_out ( f , " segment%u { " , count ) ;
_inc_indent ( f ) ;
2001-12-20 19:05:14 +03:00
_out ( f , " start_extent = %u " , seg - > le ) ;
2001-12-11 15:16:58 +03:00
_out_size ( f , seg - > len * vg - > extent_size , " extent_count = %u " , seg - > len ) ;
_out ( f , " stripes = %u " , seg - > stripes ) ;
if ( seg - > stripes > 1 )
2001-12-20 14:52:54 +03:00
_out_size ( f , seg - > stripe_size ,
" stripe_size = %u " , seg - > stripe_size ) ;
2001-12-11 15:16:58 +03:00
_nl ( f ) ;
_out ( f , " areas = [ " ) ;
_inc_indent ( f ) ;
for ( s = 0 ; s < seg - > stripes ; s + + ) {
2001-12-20 14:52:54 +03:00
if ( ! ( name = _get_pv_name ( f , seg - > area [ s ] . pv ) ) ) {
2001-12-11 15:16:58 +03:00
stack ;
return 0 ;
}
_out ( f , " \" %s \" , %u%s " , name , seg - > area [ s ] . pe ,
last ? " " : " , " ) ;
}
_dec_indent ( f ) ;
_out ( f , " ] " ) ;
_dec_indent ( f ) ;
_out ( f , " } " ) ;
return 1 ;
}
2001-12-20 14:52:54 +03:00
static int _count_segments ( struct logical_volume * lv )
{
int r = 0 ;
struct list * segh ;
list_iterate ( segh , & lv - > segments )
r + + ;
return r ;
}
2001-12-11 15:16:58 +03:00
static int _print_lvs ( struct formatter * f , struct volume_group * vg )
{
struct list * lvh , * segh ;
struct logical_volume * lv ;
struct stripe_segment * seg ;
char buffer [ 256 ] ;
int seg_count = 1 ;
_out ( f , " logical_volumes { " ) ;
_nl ( f ) ;
_inc_indent ( f ) ;
list_iterate ( lvh , & vg - > lvs ) {
lv = & list_item ( lvh , struct lv_list ) - > lv ;
_out ( f , " %s { " , lv - > name ) ;
_inc_indent ( f ) ;
2001-12-20 14:52:54 +03:00
if ( ! print_flags ( lv - > status , LV_FLAGS ,
buffer , sizeof ( buffer ) ) ) {
2001-12-11 15:16:58 +03:00
stack ;
return 0 ;
}
2001-12-20 19:05:14 +03:00
_out ( f , " status = %s " , buffer ) ;
2001-12-11 15:16:58 +03:00
_out ( f , " read_ahead = %u " , lv - > read_ahead ) ;
_out ( f , " segment_count = %u " , _count_segments ( lv ) ) ;
_nl ( f ) ;
list_iterate ( segh , & lv - > segments ) {
seg = list_item ( segh , struct stripe_segment ) ;
2001-12-20 14:52:54 +03:00
if ( ! _print_segment ( f , vg , seg_count + + , seg ,
( segh - > n = = & lv - > segments ) ) ) {
2001-12-11 15:16:58 +03:00
stack ;
return 0 ;
}
}
_dec_indent ( f ) ;
2001-12-20 19:05:14 +03:00
_out ( f , " } " ) ;
2001-12-11 15:16:58 +03:00
}
_dec_indent ( f ) ;
2001-12-20 19:05:14 +03:00
_out ( f , " } " ) ;
2001-12-11 15:16:58 +03:00
return 1 ;
}
/*
* In the text format we refer to pv ' s as ' pv1 ' ,
* ' pv2 ' etc . This function builds a hash table
* to enable a quick lookup from device - > name .
*/
static int _build_pv_names ( struct formatter * f ,
struct volume_group * vg )
{
int count = 0 ;
struct list * pvh ;
struct physical_volume * pv ;
char buffer [ 32 ] , * name ;
if ( ! ( f - > mem = pool_create ( 512 ) ) ) {
stack ;
goto bad ;
}
if ( ! ( f - > pv_names = hash_create ( 128 ) ) ) {
stack ;
goto bad ;
}
list_iterate ( pvh , & vg - > pvs ) {
pv = & list_item ( pvh , struct pv_list ) - > pv ;
2001-12-20 19:05:14 +03:00
if ( lvm_snprintf ( buffer , sizeof ( buffer ) ,
" pv%d " , count + + ) < 0 ) {
2001-12-11 15:16:58 +03:00
stack ;
goto bad ;
}
if ( ! ( name = pool_strdup ( f - > mem , buffer ) ) ) {
stack ;
goto bad ;
}
2001-12-20 19:05:14 +03:00
if ( ! hash_insert ( f - > pv_names , dev_name ( pv - > dev ) , name ) ) {
2001-12-11 15:16:58 +03:00
stack ;
goto bad ;
}
}
return 1 ;
bad :
if ( f - > mem )
pool_destroy ( f - > mem ) ;
if ( f - > pv_names )
hash_destroy ( f - > pv_names ) ;
return 0 ;
}
int text_vg_export ( FILE * fp , struct volume_group * vg )
{
int r = 0 ;
struct formatter * f ;
2001-12-20 14:52:54 +03:00
if ( ! ( f = dbg_malloc ( sizeof ( * f ) ) ) ) {
2001-12-11 15:16:58 +03:00
stack ;
return 0 ;
}
memset ( f , 0 , sizeof ( * f ) ) ;
f - > fp = fp ;
f - > indent = 0 ;
if ( ! _build_pv_names ( f , vg ) ) {
stack ;
goto out ;
}
# define fail do {stack; goto out;} while(0)
if ( ! _print_header ( f , vg ) )
fail ;
_out ( f , " %s { " , vg - > name ) ;
2001-12-20 14:52:54 +03:00
_inc_indent ( f ) ;
2001-12-11 15:16:58 +03:00
if ( ! _print_vg ( f , vg ) )
fail ;
2001-12-31 18:14:44 +03:00
_nl ( f ) ;
2001-12-20 19:05:14 +03:00
2001-12-11 15:16:58 +03:00
if ( ! _print_pvs ( f , vg ) )
fail ;
2001-12-20 19:05:14 +03:00
_nl ( f ) ;
2001-12-11 15:16:58 +03:00
if ( ! _print_lvs ( f , vg ) )
fail ;
# undef fail
_dec_indent ( f ) ;
_out ( f , " } " ) ;
2001-12-20 19:05:14 +03:00
r = ! ferror ( f - > fp ) ;
2001-12-11 15:16:58 +03:00
out :
if ( f - > mem )
pool_destroy ( f - > mem ) ;
if ( f - > pv_names )
hash_destroy ( f - > pv_names ) ;
2001-12-20 14:52:54 +03:00
dbg_free ( f ) ;
2001-12-11 15:16:58 +03:00
return r ;
}