2002-12-12 23:55:49 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2002 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2002-12-12 23:55:49 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2002-12-12 23:55:49 +03:00
*
2004-03-30 23:35:44 +04:00
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
2002-12-12 23:55:49 +03:00
*
2004-03-30 23:35:44 +04:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2002-12-12 23:55:49 +03:00
*/
# include "lib.h"
# include "metadata.h"
# include "report.h"
# include "toolcontext.h"
# include "lvm-string.h"
# include "display.h"
# include "activate.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2006-10-03 21:55:20 +04:00
# include "str_list.h"
2002-12-12 23:55:49 +03:00
/*
* For macro use
*/
static union {
struct physical_volume _pv ;
struct logical_volume _lv ;
struct volume_group _vg ;
struct lv_segment _seg ;
2005-04-20 00:58:25 +04:00
struct pv_segment _pvseg ;
2002-12-12 23:55:49 +03:00
} _dummy ;
/*
* Report handle flags
*/
# define RH_SORT_REQUIRED 0x00000001
# define RH_HEADINGS_PRINTED 0x00000002
# define RH_BUFFERED 0x00000004
# define RH_ALIGNED 0x00000008
# define RH_HEADINGS 0x00000010
struct report_handle {
struct cmd_context * cmd ;
2005-10-17 03:03:59 +04:00
struct dm_pool * mem ;
2002-12-12 23:55:49 +03:00
report_type_t type ;
2002-12-20 02:25:55 +03:00
const char * field_prefix ;
2002-12-12 23:55:49 +03:00
uint32_t flags ;
const char * separator ;
uint32_t keys_count ;
/* Ordered list of fields needed for this report */
struct list field_props ;
/* Rows of report data */
struct list rows ;
} ;
/*
* Per - field flags
*/
# define FLD_ALIGN_LEFT 0x00000001
# define FLD_ALIGN_RIGHT 0x00000002
# define FLD_STRING 0x00000004
# define FLD_NUMBER 0x00000008
# define FLD_HIDDEN 0x00000010
# define FLD_SORT_KEY 0x00000020
# define FLD_ASCENDING 0x00000040
# define FLD_DESCENDING 0x00000080
struct field_properties {
struct list list ;
uint32_t field_num ;
uint32_t sort_posn ;
int width ;
uint32_t flags ;
} ;
/*
* Report data
*/
struct field {
struct list list ;
struct field_properties * props ;
2002-12-20 02:25:55 +03:00
const char * report_string ; /* Formatted ready for display */
const void * sort_value ; /* Raw value for sorting */
2002-12-12 23:55:49 +03:00
} ;
struct row {
struct list list ;
struct report_handle * rh ;
struct list fields ; /* Fields in display order */
struct field * ( * sort_fields ) [ ] ; /* Fields in sort order */
} ;
2004-05-19 02:12:53 +04:00
static char _alloc_policy_char ( alloc_policy_t alloc )
{
switch ( alloc ) {
case ALLOC_CONTIGUOUS :
return ' c ' ;
2006-10-08 16:01:13 +04:00
case ALLOC_CLING :
return ' C ' ;
2004-05-19 02:12:53 +04:00
case ALLOC_NORMAL :
return ' n ' ;
case ALLOC_ANYWHERE :
return ' a ' ;
default :
return ' i ' ;
}
}
2002-12-12 23:55:49 +03:00
/*
* Data - munging functions to prepare each data type for display and sorting
*/
static int _string_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
if ( !
( field - > report_string =
2005-10-17 03:03:59 +04:00
dm_pool_strdup ( rh - > mem , * ( const char * * ) data ) ) ) {
log_error ( " dm_pool_strdup failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2002-12-20 02:25:55 +03:00
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _dev_name_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const char * name = dev_name ( * ( const struct device * * ) data ) ;
2002-12-12 23:55:49 +03:00
return _string_disp ( rh , field , & name ) ;
}
2004-05-05 14:58:44 +04:00
static int _devices_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct lv_segment * seg = ( const struct lv_segment * ) data ;
unsigned int s ;
2005-10-17 03:03:59 +04:00
const char * name = NULL ;
uint32_t extent = 0 ;
2004-05-05 14:58:44 +04:00
char extent_str [ 32 ] ;
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_begin_object ( rh - > mem , 256 ) ) {
log_error ( " dm_pool_begin_object failed " ) ;
2004-05-05 14:58:44 +04:00
return 0 ;
}
for ( s = 0 ; s < seg - > area_count ; s + + ) {
2005-06-01 20:51:55 +04:00
switch ( seg_type ( seg , s ) ) {
2004-05-05 14:58:44 +04:00
case AREA_LV :
2005-06-01 20:51:55 +04:00
name = seg_lv ( seg , s ) - > name ;
extent = seg_le ( seg , s ) ;
2004-05-05 14:58:44 +04:00
break ;
case AREA_PV :
2005-06-01 20:51:55 +04:00
name = dev_name ( seg_dev ( seg , s ) ) ;
extent = seg_pe ( seg , s ) ;
2004-05-05 14:58:44 +04:00
break ;
2005-06-14 21:54:48 +04:00
case AREA_UNASSIGNED :
name = " unassigned " ;
2004-05-05 14:58:44 +04:00
extent = 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , name , strlen ( name ) ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
2004-05-05 14:58:44 +04:00
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( extent_str , sizeof ( extent_str ) , " (% " PRIu32
2004-05-05 14:58:44 +04:00
" ) " , extent ) < 0 ) {
2006-08-21 16:54:53 +04:00
log_error ( " Extent number dm_snprintf failed " ) ;
2004-05-05 14:58:44 +04:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , extent_str , strlen ( extent_str ) ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
2004-05-05 14:58:44 +04:00
return 0 ;
}
if ( ( s ! = seg - > area_count - 1 ) & &
2005-10-17 03:03:59 +04:00
! dm_pool_grow_object ( rh - > mem , " , " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
2004-05-05 14:58:44 +04:00
return 0 ;
}
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
2004-05-05 14:58:44 +04:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
field - > report_string = dm_pool_end_object ( rh - > mem ) ;
2004-05-05 14:58:44 +04:00
field - > sort_value = ( const void * ) field - > report_string ;
return 1 ;
}
2006-10-03 21:55:20 +04:00
2004-03-08 20:19:15 +03:00
static int _tags_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct list * tags = ( const struct list * ) data ;
struct str_list * sl ;
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_begin_object ( rh - > mem , 256 ) ) {
log_error ( " dm_pool_begin_object failed " ) ;
2004-03-08 20:19:15 +03:00
return 0 ;
}
list_iterate_items ( sl , tags ) {
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , sl - > str , strlen ( sl - > str ) ) | |
( sl - > list . n ! = tags & & ! dm_pool_grow_object ( rh - > mem , " , " , 1 ) ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
2004-03-08 20:19:15 +03:00
return 0 ;
}
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
2004-03-08 20:19:15 +03:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
field - > report_string = dm_pool_end_object ( rh - > mem ) ;
2004-03-08 20:19:15 +03:00
field - > sort_value = ( const void * ) field - > report_string ;
return 1 ;
}
2006-10-03 21:55:20 +04:00
static int _modules_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
struct list * modules ;
if ( ! ( modules = str_list_create ( rh - > mem ) ) ) {
log_error ( " modules str_list allocation failed " ) ;
return 0 ;
}
if ( ! list_lv_modules ( rh - > mem , lv , modules ) )
return_0 ;
return _tags_disp ( rh , field , modules ) ;
}
2002-12-12 23:55:49 +03:00
static int _vgfmt_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct volume_group * vg = ( const struct volume_group * ) data ;
2002-12-12 23:55:49 +03:00
if ( ! vg - > fid ) {
field - > report_string = " " ;
2002-12-20 02:25:55 +03:00
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
return _string_disp ( rh , field , & vg - > fid - > fmt - > name ) ;
}
static int _pvfmt_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct physical_volume * pv =
( const struct physical_volume * ) data ;
2002-12-12 23:55:49 +03:00
if ( ! pv - > fmt ) {
field - > report_string = " " ;
2002-12-20 02:25:55 +03:00
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
return _string_disp ( rh , field , & pv - > fmt - > name ) ;
}
2004-07-04 02:07:52 +04:00
static int _int_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const int value = * ( const int * ) data ;
uint64_t * sortval ;
char * repstr ;
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 13 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2004-07-04 02:07:52 +04:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( int64_t ) ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2004-07-04 02:07:52 +04:00
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( repstr , 12 , " %d " , value ) < 0 ) {
2004-07-04 02:07:52 +04:00
log_error ( " int too big: %d " , value ) ;
return 0 ;
}
* sortval = ( const uint64_t ) value ;
field - > sort_value = sortval ;
field - > report_string = repstr ;
return 1 ;
}
static int _lvkmaj_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
struct lvinfo info ;
uint64_t minusone = UINT64_C ( - 1 ) ;
2005-10-17 22:00:02 +04:00
if ( lv_info ( lv - > vg - > cmd , lv , & info , 0 ) & & info . exists )
2004-07-04 02:07:52 +04:00
return _int_disp ( rh , field , & info . major ) ;
else
return _int_disp ( rh , field , & minusone ) ;
return 1 ;
}
static int _lvkmin_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
struct lvinfo info ;
uint64_t minusone = UINT64_C ( - 1 ) ;
2005-10-17 22:00:02 +04:00
if ( lv_info ( lv - > vg - > cmd , lv , & info , 0 ) & & info . exists )
2004-07-04 02:07:52 +04:00
return _int_disp ( rh , field , & info . minor ) ;
else
return _int_disp ( rh , field , & minusone ) ;
return 1 ;
}
2002-12-12 23:55:49 +03:00
static int _lvstatus_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
2003-01-09 01:44:07 +03:00
struct lvinfo info ;
2002-12-20 02:25:55 +03:00
char * repstr ;
2003-01-21 21:50:50 +03:00
float snap_percent ;
2002-12-12 23:55:49 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 7 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2003-05-06 16:06:02 +04:00
if ( lv - > status & PVMOVE )
repstr [ 0 ] = ' p ' ;
2006-05-12 00:17:17 +04:00
else if ( lv - > status & MIRRORED ) {
if ( lv - > status & MIRROR_NOTSYNCED )
repstr [ 0 ] = ' M ' ;
else
repstr [ 0 ] = ' m ' ;
} else if ( lv - > status & MIRROR_IMAGE )
2005-06-03 18:49:51 +04:00
repstr [ 0 ] = ' i ' ;
2005-06-01 20:51:55 +04:00
else if ( lv - > status & MIRROR_LOG )
repstr [ 0 ] = ' l ' ;
2004-05-11 20:01:58 +04:00
else if ( lv - > status & VIRTUAL )
repstr [ 0 ] = ' v ' ;
2003-05-06 16:06:02 +04:00
else if ( lv_is_origin ( lv ) )
2002-12-20 02:25:55 +03:00
repstr [ 0 ] = ' o ' ;
2006-04-06 17:39:16 +04:00
else if ( lv_is_cow ( lv ) )
2002-12-20 02:25:55 +03:00
repstr [ 0 ] = ' s ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 0 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
2003-05-06 16:06:02 +04:00
if ( lv - > status & PVMOVE )
repstr [ 1 ] = ' - ' ;
else if ( lv - > status & LVM_WRITE )
2002-12-20 02:25:55 +03:00
repstr [ 1 ] = ' w ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 1 ] = ' r ' ;
2002-12-12 23:55:49 +03:00
2004-05-19 02:12:53 +04:00
repstr [ 2 ] = _alloc_policy_char ( lv - > alloc ) ;
2002-12-12 23:55:49 +03:00
2003-05-06 16:06:02 +04:00
if ( lv - > status & LOCKED )
repstr [ 2 ] = toupper ( repstr [ 2 ] ) ;
2002-12-12 23:55:49 +03:00
if ( lv - > status & FIXED_MINOR )
2002-12-20 02:25:55 +03:00
repstr [ 3 ] = ' m ' ; /* Fixed Minor */
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 3 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
2005-10-17 22:00:02 +04:00
if ( lv_info ( lv - > vg - > cmd , lv , & info , 1 ) & & info . exists ) {
2002-12-12 23:55:49 +03:00
if ( info . suspended )
2002-12-20 02:25:55 +03:00
repstr [ 4 ] = ' s ' ; /* Suspended */
2005-11-09 01:52:26 +03:00
else if ( info . live_table )
2002-12-20 02:25:55 +03:00
repstr [ 4 ] = ' a ' ; /* Active */
2005-11-09 01:52:26 +03:00
else if ( info . inactive_table )
repstr [ 4 ] = ' i ' ; /* Inactive with table */
2002-12-12 23:55:49 +03:00
else
2005-11-09 01:52:26 +03:00
repstr [ 4 ] = ' d ' ; /* Inactive without table */
2003-01-21 21:50:50 +03:00
/* Snapshot dropped? */
2006-04-06 17:39:16 +04:00
if ( info . live_table & & lv_is_cow ( lv ) & &
2006-04-06 18:06:27 +04:00
( ! lv_snapshot_percent ( lv , & snap_percent ) | |
2003-07-05 02:34:56 +04:00
snap_percent < 0 | | snap_percent > = 100 ) ) {
2003-01-21 21:50:50 +03:00
repstr [ 0 ] = toupper ( repstr [ 0 ] ) ;
2003-07-05 02:34:56 +04:00
if ( info . suspended )
2005-11-09 01:52:26 +03:00
repstr [ 4 ] = ' S ' ; /* Susp Inv snapshot */
2003-07-05 02:34:56 +04:00
else
2005-11-09 01:52:26 +03:00
repstr [ 4 ] = ' I ' ; /* Invalid snapshot */
2003-07-05 02:34:56 +04:00
}
2003-01-21 21:50:50 +03:00
2005-11-09 01:52:26 +03:00
if ( info . open_count )
repstr [ 5 ] = ' o ' ; /* Open */
else
repstr [ 5 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
} else {
2002-12-20 02:25:55 +03:00
repstr [ 4 ] = ' - ' ;
repstr [ 5 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
}
2002-12-20 02:25:55 +03:00
field - > report_string = repstr ;
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _pvstatus_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const uint32_t status = * ( const uint32_t * ) data ;
char * repstr ;
2002-12-12 23:55:49 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 4 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
if ( status & ALLOCATABLE_PV )
2002-12-20 02:25:55 +03:00
repstr [ 0 ] = ' a ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 0 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
if ( status & EXPORTED_VG )
2002-12-20 02:25:55 +03:00
repstr [ 1 ] = ' x ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 1 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
2002-12-20 02:25:55 +03:00
field - > report_string = repstr ;
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _vgstatus_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2004-05-19 02:12:53 +04:00
const struct volume_group * vg = ( const struct volume_group * ) data ;
2002-12-20 02:25:55 +03:00
char * repstr ;
2002-12-12 23:55:49 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 7 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2004-05-19 02:12:53 +04:00
if ( vg - > status & LVM_WRITE )
2002-12-20 02:25:55 +03:00
repstr [ 0 ] = ' w ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 0 ] = ' r ' ;
2002-12-12 23:55:49 +03:00
2004-05-19 02:12:53 +04:00
if ( vg - > status & RESIZEABLE_VG )
2002-12-20 02:25:55 +03:00
repstr [ 1 ] = ' z ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 1 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
2004-05-19 02:12:53 +04:00
if ( vg - > status & EXPORTED_VG )
2002-12-20 02:25:55 +03:00
repstr [ 2 ] = ' x ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 2 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
2004-05-19 02:12:53 +04:00
if ( vg - > status & PARTIAL_VG )
2002-12-20 02:25:55 +03:00
repstr [ 3 ] = ' p ' ;
2002-12-12 23:55:49 +03:00
else
2002-12-20 02:25:55 +03:00
repstr [ 3 ] = ' - ' ;
2002-12-12 23:55:49 +03:00
2004-05-19 02:12:53 +04:00
repstr [ 4 ] = _alloc_policy_char ( vg - > alloc ) ;
2005-08-16 03:34:11 +04:00
if ( vg - > status & CLUSTERED )
repstr [ 5 ] = ' c ' ;
else
repstr [ 5 ] = ' - ' ;
2002-12-20 02:25:55 +03:00
field - > report_string = repstr ;
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
2006-05-11 21:58:58 +04:00
static int _segtype_disp ( struct report_handle * rh __attribute ( ( unused ) ) ,
struct field * field ,
2002-12-12 23:55:49 +03:00
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct lv_segment * seg = ( const struct lv_segment * ) data ;
2002-12-12 23:55:49 +03:00
2003-04-25 02:23:24 +04:00
if ( seg - > area_count = = 1 )
2002-12-12 23:55:49 +03:00
field - > report_string = " linear " ;
else
2004-05-05 01:25:57 +04:00
field - > report_string = seg - > segtype - > ops - > name ( seg ) ;
2002-12-20 02:25:55 +03:00
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _origin_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
2002-12-12 23:55:49 +03:00
2006-04-06 17:39:16 +04:00
if ( lv_is_cow ( lv ) )
return _string_disp ( rh , field , & origin_from_cow ( lv ) - > name ) ;
2002-12-12 23:55:49 +03:00
field - > report_string = " " ;
2002-12-20 02:25:55 +03:00
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
2005-06-01 20:51:55 +04:00
static int _loglv_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
struct lv_segment * seg ;
list_iterate_items ( seg , & lv - > segments ) {
if ( ! seg_is_mirrored ( seg ) | | ! seg - > log_lv )
continue ;
return _string_disp ( rh , field , & seg - > log_lv - > name ) ;
}
field - > report_string = " " ;
field - > sort_value = ( const void * ) field - > report_string ;
return 1 ;
}
2005-06-03 18:49:51 +04:00
static int _lvname_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
char * repstr ;
size_t len ;
2006-04-07 21:41:56 +04:00
if ( lv_is_visible ( lv ) ) {
2005-06-03 18:49:51 +04:00
repstr = lv - > name ;
return _string_disp ( rh , field , & repstr ) ;
}
len = strlen ( lv - > name ) + 3 ;
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , len ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2005-06-03 18:49:51 +04:00
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( repstr , len , " [%s] " , lv - > name ) < 0 ) {
2005-06-03 18:49:51 +04:00
log_error ( " lvname snprintf failed " ) ;
return 0 ;
}
field - > report_string = repstr ;
2005-10-17 03:03:59 +04:00
if ( ! ( field - > sort_value = dm_pool_strdup ( rh - > mem , lv - > name ) ) ) {
log_error ( " dm_pool_strdup failed " ) ;
2005-06-03 18:49:51 +04:00
return 0 ;
}
return 1 ;
}
2003-05-06 16:06:02 +04:00
static int _movepv_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
const char * name ;
struct lv_segment * seg ;
2005-06-01 20:51:55 +04:00
list_iterate_items ( seg , & lv - > segments ) {
2003-05-06 16:06:02 +04:00
if ( ! ( seg - > status & PVMOVE ) )
continue ;
2005-06-01 20:51:55 +04:00
name = dev_name ( seg_dev ( seg , 0 ) ) ;
2003-05-06 16:06:02 +04:00
return _string_disp ( rh , field , & name ) ;
}
field - > report_string = " " ;
field - > sort_value = ( const void * ) field - > report_string ;
return 1 ;
}
2002-12-12 23:55:49 +03:00
static int _size32_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const uint32_t size = * ( const uint32_t * ) data ;
2002-12-12 23:55:49 +03:00
const char * disp ;
2002-12-20 02:25:55 +03:00
uint64_t * sortval ;
2002-12-12 23:55:49 +03:00
2006-05-10 01:23:51 +04:00
if ( ! * ( disp = display_size_units ( rh - > cmd , ( uint64_t ) size ) ) ) {
2002-12-12 23:55:49 +03:00
stack ;
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( field - > report_string = dm_pool_strdup ( rh - > mem , disp ) ) ) {
log_error ( " dm_pool_strdup failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( uint64_t ) ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2002-12-20 02:25:55 +03:00
* sortval = ( const uint64_t ) size ;
field - > sort_value = ( const void * ) sortval ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _size64_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const uint64_t size = * ( const uint64_t * ) data ;
2002-12-12 23:55:49 +03:00
const char * disp ;
2002-12-20 02:25:55 +03:00
uint64_t * sortval ;
2002-12-12 23:55:49 +03:00
2006-05-10 01:23:51 +04:00
if ( ! * ( disp = display_size_units ( rh - > cmd , size ) ) ) {
2002-12-12 23:55:49 +03:00
stack ;
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( field - > report_string = dm_pool_strdup ( rh - > mem , disp ) ) ) {
log_error ( " dm_pool_strdup failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( uint64_t ) ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2002-12-20 02:25:55 +03:00
* sortval = size ;
field - > sort_value = sortval ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _vgsize_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct volume_group * vg = ( const struct volume_group * ) data ;
2002-12-12 23:55:49 +03:00
uint64_t size ;
2005-02-01 19:19:48 +03:00
size = ( uint64_t ) vg - > extent_count * vg - > extent_size ;
2002-12-12 23:55:49 +03:00
return _size64_disp ( rh , field , & size ) ;
}
static int _segstart_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct lv_segment * seg = ( const struct lv_segment * ) data ;
2002-12-12 23:55:49 +03:00
uint64_t start ;
2005-02-01 19:19:48 +03:00
start = ( uint64_t ) seg - > le * seg - > lv - > vg - > extent_size ;
2002-12-12 23:55:49 +03:00
return _size64_disp ( rh , field , & start ) ;
}
static int _segsize_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct lv_segment * seg = ( const struct lv_segment * ) data ;
2002-12-12 23:55:49 +03:00
uint64_t size ;
2005-02-01 19:19:48 +03:00
size = ( uint64_t ) seg - > len * seg - > lv - > vg - > extent_size ;
2002-12-12 23:55:49 +03:00
return _size64_disp ( rh , field , & size ) ;
}
2005-09-23 21:06:01 +04:00
static int _chunksize_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct lv_segment * seg = ( const struct lv_segment * ) data ;
uint64_t size ;
2006-04-06 17:39:16 +04:00
if ( lv_is_cow ( seg - > lv ) )
size = ( uint64_t ) find_cow ( seg - > lv ) - > chunk_size ;
2005-09-23 21:06:01 +04:00
else
size = 0 ;
return _size64_disp ( rh , field , & size ) ;
}
2002-12-12 23:55:49 +03:00
static int _pvused_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct physical_volume * pv =
( const struct physical_volume * ) data ;
2002-12-12 23:55:49 +03:00
uint64_t used ;
if ( ! pv - > pe_count )
used = 0LL ;
else
2005-02-01 19:19:48 +03:00
used = ( uint64_t ) pv - > pe_alloc_count * pv - > pe_size ;
2002-12-12 23:55:49 +03:00
return _size64_disp ( rh , field , & used ) ;
}
static int _pvfree_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct physical_volume * pv =
( const struct physical_volume * ) data ;
uint64_t freespace ;
2002-12-12 23:55:49 +03:00
if ( ! pv - > pe_count )
2002-12-20 02:25:55 +03:00
freespace = pv - > size ;
2002-12-12 23:55:49 +03:00
else
2005-02-01 19:19:48 +03:00
freespace = ( uint64_t ) ( pv - > pe_count - pv - > pe_alloc_count ) * pv - > pe_size ;
2002-12-12 23:55:49 +03:00
2002-12-20 02:25:55 +03:00
return _size64_disp ( rh , field , & freespace ) ;
2002-12-12 23:55:49 +03:00
}
static int _pvsize_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct physical_volume * pv =
( const struct physical_volume * ) data ;
2002-12-12 23:55:49 +03:00
uint64_t size ;
if ( ! pv - > pe_count )
size = pv - > size ;
else
2005-02-01 19:19:48 +03:00
size = ( uint64_t ) pv - > pe_count * pv - > pe_size ;
2002-12-12 23:55:49 +03:00
return _size64_disp ( rh , field , & size ) ;
}
2004-08-11 17:15:05 +04:00
static int _devsize_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
const struct device * dev = * ( const struct device * * ) data ;
uint64_t size ;
if ( ! dev_get_size ( dev , & size ) )
size = 0 ;
return _size64_disp ( rh , field , & size ) ;
}
2002-12-12 23:55:49 +03:00
static int _vgfree_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct volume_group * vg = ( const struct volume_group * ) data ;
uint64_t freespace ;
2002-12-12 23:55:49 +03:00
2005-02-01 19:19:48 +03:00
freespace = ( uint64_t ) vg - > free_count * vg - > extent_size ;
2002-12-12 23:55:49 +03:00
2002-12-20 02:25:55 +03:00
return _size64_disp ( rh , field , & freespace ) ;
2002-12-12 23:55:49 +03:00
}
static int _uuid_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
char * repstr = NULL ;
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_alloc ( rh - > mem , 40 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2002-12-20 02:25:55 +03:00
if ( ! id_write_format ( ( const struct id * ) data , repstr , 40 ) ) {
2002-12-12 23:55:49 +03:00
stack ;
return 0 ;
}
2002-12-20 02:25:55 +03:00
field - > report_string = repstr ;
field - > sort_value = ( const void * ) field - > report_string ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _uint32_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const uint32_t value = * ( const uint32_t * ) data ;
uint64_t * sortval ;
char * repstr ;
2002-12-12 23:55:49 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 12 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( uint64_t ) ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( repstr , 11 , " %u " , value ) < 0 ) {
2002-12-12 23:55:49 +03:00
log_error ( " uint32 too big: %u " , value ) ;
return 0 ;
}
2002-12-20 02:25:55 +03:00
* sortval = ( const uint64_t ) value ;
field - > sort_value = sortval ;
field - > report_string = repstr ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _int32_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const int32_t value = * ( const int32_t * ) data ;
uint64_t * sortval ;
char * repstr ;
2002-12-12 23:55:49 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 13 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( int64_t ) ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( repstr , 12 , " %d " , value ) < 0 ) {
2002-12-12 23:55:49 +03:00
log_error ( " int32 too big: %d " , value ) ;
return 0 ;
}
2002-12-20 02:25:55 +03:00
* sortval = ( const uint64_t ) value ;
field - > sort_value = sortval ;
field - > report_string = repstr ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
static int _lvsegcount_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
2002-12-12 23:55:49 +03:00
uint32_t count ;
count = list_size ( & lv - > segments ) ;
return _uint32_disp ( rh , field , & count ) ;
}
static int _snpercent_disp ( struct report_handle * rh , struct field * field ,
const void * data )
{
2002-12-20 02:25:55 +03:00
const struct logical_volume * lv = ( const struct logical_volume * ) data ;
2003-07-05 02:34:56 +04:00
struct lvinfo info ;
2002-12-12 23:55:49 +03:00
float snap_percent ;
2002-12-20 02:25:55 +03:00
uint64_t * sortval ;
char * repstr ;
2002-12-12 23:55:49 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( uint64_t ) ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2006-04-06 18:06:27 +04:00
if ( ! lv_is_cow ( lv ) | |
( lv_info ( lv - > vg - > cmd , lv , & info , 0 ) & & ! info . exists ) ) {
2002-12-12 23:55:49 +03:00
field - > report_string = " " ;
2003-03-24 21:08:53 +03:00
* sortval = UINT64_C ( 0 ) ;
2002-12-20 02:25:55 +03:00
field - > sort_value = sortval ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
2006-04-06 18:06:27 +04:00
if ( ! lv_snapshot_percent ( lv , & snap_percent ) | | snap_percent < 0 ) {
2003-01-21 21:50:50 +03:00
field - > report_string = " 100.00 " ;
2003-03-24 21:08:53 +03:00
* sortval = UINT64_C ( 100 ) ;
2003-01-21 21:50:50 +03:00
field - > sort_value = sortval ;
return 1 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 8 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( repstr , 7 , " %.2f " , snap_percent ) < 0 ) {
2002-12-12 23:55:49 +03:00
log_error ( " snapshot percentage too large " ) ;
return 0 ;
}
2003-03-24 21:08:53 +03:00
* sortval = snap_percent * UINT64_C ( 1000 ) ;
2002-12-20 02:25:55 +03:00
field - > sort_value = sortval ;
field - > report_string = repstr ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
2004-05-05 14:58:44 +04:00
static int _copypercent_disp ( struct report_handle * rh , struct field * field ,
2003-05-06 16:06:02 +04:00
const void * data )
{
struct logical_volume * lv = ( struct logical_volume * ) data ;
2004-05-05 14:58:44 +04:00
float percent ;
2003-05-06 16:06:02 +04:00
uint64_t * sortval ;
char * repstr ;
2005-10-17 03:03:59 +04:00
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( uint64_t ) ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2003-05-06 16:06:02 +04:00
return 0 ;
}
2004-05-05 22:23:11 +04:00
if ( ( ! ( lv - > status & PVMOVE ) & & ! ( lv - > status & MIRRORED ) ) | |
2005-10-17 22:00:02 +04:00
! lv_mirror_percent ( lv - > vg - > cmd , lv , 0 , & percent , NULL ) ) {
2003-05-06 16:06:02 +04:00
field - > report_string = " " ;
* sortval = UINT64_C ( 0 ) ;
field - > sort_value = sortval ;
return 1 ;
}
2004-05-05 21:56:20 +04:00
percent = copy_percent ( lv ) ;
2003-05-06 16:06:02 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( repstr = dm_pool_zalloc ( rh - > mem , 8 ) ) ) {
log_error ( " dm_pool_alloc failed " ) ;
2003-05-06 16:06:02 +04:00
return 0 ;
}
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( repstr , 7 , " %.2f " , percent ) < 0 ) {
2004-05-05 14:58:44 +04:00
log_error ( " copy percentage too large " ) ;
2003-05-06 16:06:02 +04:00
return 0 ;
}
2004-05-05 14:58:44 +04:00
* sortval = percent * UINT64_C ( 1000 ) ;
2003-05-06 16:06:02 +04:00
field - > sort_value = sortval ;
field - > report_string = repstr ;
return 1 ;
}
2002-12-12 23:55:49 +03:00
/*
* Import column definitions
*/
# define STR (FLD_STRING | FLD_ALIGN_LEFT)
# define NUM (FLD_NUMBER | FLD_ALIGN_RIGHT)
# define FIELD(type, strct, sorttype, head, field, width, func, id) {type, id, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), head, width, sorttype, &_ ## func ## _disp},
static struct {
report_type_t type ;
2005-04-06 17:47:41 +04:00
const char id [ 32 ] ;
2002-12-12 23:55:49 +03:00
off_t offset ;
2005-04-06 17:47:41 +04:00
const char heading [ 32 ] ;
2002-12-12 23:55:49 +03:00
int width ;
uint32_t flags ;
field_report_fn report_fn ;
} _fields [ ] = {
# include "columns.h"
} ;
# undef STR
# undef NUM
# undef FIELD
2002-12-20 02:25:55 +03:00
const unsigned int _num_fields = sizeof ( _fields ) / sizeof ( _fields [ 0 ] ) ;
2002-12-12 23:55:49 +03:00
2006-10-02 20:46:27 +04:00
static void _display_fields ( void )
{
uint32_t f ;
const char * type , * last_type = " " ;
for ( f = 0 ; f < _num_fields ; f + + ) {
switch ( _fields [ f ] . type ) {
case PVS :
type = " Physical Volume " ;
break ;
case LVS :
type = " Logical Volume " ;
break ;
case VGS :
type = " Volume Group " ;
break ;
case SEGS :
type = " Logical Volume Segment " ;
break ;
case PVSEGS :
type = " Physical Volume Segment " ;
break ;
default :
type = " " ;
}
if ( type ! = last_type ) {
if ( * last_type )
log_print ( " " ) ;
log_print ( " %s Fields " , type ) ;
}
log_print ( " - %s " , _fields [ f ] . id ) ;
last_type = type ;
}
}
2002-12-12 23:55:49 +03:00
/*
* Initialise report handle
*/
2002-12-20 02:25:55 +03:00
static int _field_match ( struct report_handle * rh , const char * field , size_t len )
2002-12-12 23:55:49 +03:00
{
uint32_t f , l ;
struct field_properties * fp ;
if ( ! len )
return 0 ;
for ( f = 0 ; f < _num_fields ; f + + ) {
if ( ( ! strncasecmp ( _fields [ f ] . id , field , len ) & &
strlen ( _fields [ f ] . id ) = = len ) | |
( l = strlen ( rh - > field_prefix ) ,
! strncasecmp ( rh - > field_prefix , _fields [ f ] . id , l ) & &
! strncasecmp ( _fields [ f ] . id + l , field , len ) & &
strlen ( _fields [ f ] . id ) = = l + len ) ) {
rh - > type | = _fields [ f ] . type ;
2005-10-17 03:03:59 +04:00
if ( ! ( fp = dm_pool_zalloc ( rh - > mem , sizeof ( * fp ) ) ) ) {
2002-12-12 23:55:49 +03:00
log_error ( " struct field_properties allocation "
" failed " ) ;
return 0 ;
}
fp - > field_num = f ;
fp - > width = _fields [ f ] . width ;
fp - > flags = _fields [ f ] . flags ;
/* Suppress snapshot percentage if not using driver */
if ( ! activation ( )
& & ! strncmp ( field , " snap_percent " , len ) )
fp - > flags | = FLD_HIDDEN ;
list_add ( & rh - > field_props , & fp - > list ) ;
return 1 ;
}
}
return 0 ;
}
static int _add_sort_key ( struct report_handle * rh , uint32_t field_num ,
uint32_t flags )
{
struct field_properties * fp , * found = NULL ;
2005-06-01 20:51:55 +04:00
list_iterate_items ( fp , & rh - > field_props ) {
2002-12-12 23:55:49 +03:00
if ( fp - > field_num = = field_num ) {
found = fp ;
break ;
}
}
if ( ! found ) {
/* Add as a non-display field */
2005-10-17 03:03:59 +04:00
if ( ! ( found = dm_pool_zalloc ( rh - > mem , sizeof ( * found ) ) ) ) {
2002-12-12 23:55:49 +03:00
log_error ( " struct field_properties allocation failed " ) ;
return 0 ;
}
rh - > type | = _fields [ field_num ] . type ;
2002-12-20 02:25:55 +03:00
found - > field_num = field_num ;
found - > width = _fields [ field_num ] . width ;
found - > flags = _fields [ field_num ] . flags | FLD_HIDDEN ;
2002-12-12 23:55:49 +03:00
2002-12-20 02:25:55 +03:00
list_add ( & rh - > field_props , & found - > list ) ;
2002-12-12 23:55:49 +03:00
}
2002-12-20 02:25:55 +03:00
if ( found - > flags & FLD_SORT_KEY ) {
2002-12-12 23:55:49 +03:00
log_error ( " Ignoring duplicate sort field: %s " ,
_fields [ field_num ] . id ) ;
return 1 ;
}
2002-12-20 02:25:55 +03:00
found - > flags | = FLD_SORT_KEY ;
found - > sort_posn = rh - > keys_count + + ;
found - > flags | = flags ;
2002-12-12 23:55:49 +03:00
return 1 ;
}
2002-12-20 02:25:55 +03:00
static int _key_match ( struct report_handle * rh , const char * key , size_t len )
2002-12-12 23:55:49 +03:00
{
uint32_t f , l ;
uint32_t flags = 0 ;
if ( ! len )
return 0 ;
if ( * key = = ' + ' ) {
key + + ;
len - - ;
flags = FLD_ASCENDING ;
} else if ( * key = = ' - ' ) {
key + + ;
len - - ;
flags = FLD_DESCENDING ;
} else
flags = FLD_ASCENDING ;
if ( ! len ) {
log_error ( " Missing sort field name " ) ;
return 0 ;
}
for ( f = 0 ; f < _num_fields ; f + + ) {
if ( ( ! strncasecmp ( _fields [ f ] . id , key , len ) & &
strlen ( _fields [ f ] . id ) = = len ) | |
( l = strlen ( rh - > field_prefix ) ,
! strncasecmp ( rh - > field_prefix , _fields [ f ] . id , l ) & &
! strncasecmp ( _fields [ f ] . id + l , key , len ) & &
strlen ( _fields [ f ] . id ) = = l + len ) ) {
return _add_sort_key ( rh , f , flags ) ;
}
}
return 0 ;
}
static int _parse_options ( struct report_handle * rh , const char * format )
{
const char * ws ; /* Word start */
const char * we = format ; /* Word end */
while ( * we ) {
/* Allow consecutive commas */
while ( * we & & * we = = ' , ' )
we + + ;
ws = we ;
while ( * we & & * we ! = ' , ' )
we + + ;
2002-12-20 02:25:55 +03:00
if ( ! _field_match ( rh , ws , ( size_t ) ( we - ws ) ) ) {
2006-10-02 20:46:27 +04:00
_display_fields ( ) ;
log_print ( " " ) ;
2003-01-21 21:50:50 +03:00
log_error ( " Unrecognised field: %.*s " , ( int ) ( we - ws ) ,
ws ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
}
return 1 ;
}
static int _parse_keys ( struct report_handle * rh , const char * keys )
{
const char * ws ; /* Word start */
const char * we = keys ; /* Word end */
while ( * we ) {
/* Allow consecutive commas */
while ( * we & & * we = = ' , ' )
we + + ;
ws = we ;
while ( * we & & * we ! = ' , ' )
we + + ;
2002-12-20 02:25:55 +03:00
if ( ! _key_match ( rh , ws , ( size_t ) ( we - ws ) ) ) {
2003-01-21 21:50:50 +03:00
log_error ( " Unrecognised field: %.*s " , ( int ) ( we - ws ) ,
ws ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
}
return 1 ;
}
void * report_init ( struct cmd_context * cmd , const char * format , const char * keys ,
report_type_t * report_type , const char * separator ,
int aligned , int buffered , int headings )
{
struct report_handle * rh ;
2005-10-17 03:03:59 +04:00
if ( ! ( rh = dm_pool_zalloc ( cmd - > mem , sizeof ( * rh ) ) ) ) {
log_error ( " report_handle dm_pool_zalloc failed " ) ;
2002-12-12 23:55:49 +03:00
return 0 ;
}
rh - > cmd = cmd ;
rh - > type = * report_type ;
rh - > separator = separator ;
if ( aligned )
rh - > flags | = RH_ALIGNED ;
if ( buffered )
rh - > flags | = RH_BUFFERED | RH_SORT_REQUIRED ;
if ( headings )
rh - > flags | = RH_HEADINGS ;
list_init ( & rh - > field_props ) ;
list_init ( & rh - > rows ) ;
switch ( rh - > type ) {
case PVS :
rh - > field_prefix = " pv_ " ;
break ;
case LVS :
rh - > field_prefix = " lv_ " ;
break ;
case VGS :
rh - > field_prefix = " vg_ " ;
break ;
case SEGS :
rh - > field_prefix = " seg_ " ;
break ;
2005-04-20 00:58:25 +04:00
case PVSEGS :
rh - > field_prefix = " pvseg_ " ;
break ;
2002-12-12 23:55:49 +03:00
default :
rh - > field_prefix = " " ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( rh - > mem = dm_pool_create ( " report " , 10 * 1024 ) ) ) {
2002-12-12 23:55:49 +03:00
log_error ( " Allocation of memory pool for report failed " ) ;
return NULL ;
}
/* Generate list of fields for output based on format string & flags */
if ( ! _parse_options ( rh , format ) )
return NULL ;
if ( ! _parse_keys ( rh , keys ) )
return NULL ;
/* Ensure options selected are compatible */
if ( rh - > type & SEGS )
rh - > type | = LVS ;
2005-04-20 00:58:25 +04:00
if ( rh - > type & PVSEGS )
rh - > type | = PVS ;
2002-12-12 23:55:49 +03:00
if ( ( rh - > type & LVS ) & & ( rh - > type & PVS ) ) {
log_error ( " Can't report LV and PV fields at the same time " ) ;
return NULL ;
}
/* Change report type if fields specified makes this necessary */
if ( rh - > type & SEGS )
* report_type = SEGS ;
else if ( rh - > type & LVS )
* report_type = LVS ;
2005-04-20 00:58:25 +04:00
else if ( rh - > type & PVSEGS )
* report_type = PVSEGS ;
2002-12-12 23:55:49 +03:00
else if ( rh - > type & PVS )
* report_type = PVS ;
return rh ;
}
void report_free ( void * handle )
{
struct report_handle * rh = handle ;
2005-10-17 03:03:59 +04:00
dm_pool_destroy ( rh - > mem ) ;
2002-12-12 23:55:49 +03:00
return ;
}
/*
* Create a row of data for an object
*/
int report_object ( void * handle , struct volume_group * vg ,
struct logical_volume * lv , struct physical_volume * pv ,
2005-04-20 00:58:25 +04:00
struct lv_segment * seg , struct pv_segment * pvseg )
2002-12-12 23:55:49 +03:00
{
struct report_handle * rh = handle ;
struct field_properties * fp ;
struct row * row ;
struct field * field ;
2002-12-20 02:25:55 +03:00
void * data = NULL ;
2004-06-19 23:27:00 +04:00
int skip ;
2002-12-12 23:55:49 +03:00
if ( lv & & pv ) {
log_error ( " report_object: One of *lv and *pv must be NULL! " ) ;
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( row = dm_pool_zalloc ( rh - > mem , sizeof ( * row ) ) ) ) {
2002-12-12 23:55:49 +03:00
log_error ( " struct row allocation failed " ) ;
return 0 ;
}
row - > rh = rh ;
if ( ( rh - > flags & RH_SORT_REQUIRED ) & &
2005-10-17 03:03:59 +04:00
! ( row - > sort_fields = dm_pool_zalloc ( rh - > mem , sizeof ( struct field * ) *
2002-12-12 23:55:49 +03:00
rh - > keys_count ) ) ) {
log_error ( " row sort value structure allocation failed " ) ;
return 0 ;
}
list_init ( & row - > fields ) ;
list_add ( & rh - > rows , & row - > list ) ;
/* For each field to be displayed, call its report_fn */
2005-06-01 20:51:55 +04:00
list_iterate_items ( fp , & rh - > field_props ) {
2004-06-19 23:27:00 +04:00
skip = 0 ;
2005-10-17 03:03:59 +04:00
if ( ! ( field = dm_pool_zalloc ( rh - > mem , sizeof ( * field ) ) ) ) {
2002-12-12 23:55:49 +03:00
log_error ( " struct field allocation failed " ) ;
return 0 ;
}
field - > props = fp ;
switch ( _fields [ fp - > field_num ] . type ) {
case LVS :
data = ( void * ) lv + _fields [ fp - > field_num ] . offset ;
break ;
case VGS :
2004-06-19 23:27:00 +04:00
if ( ! vg ) {
skip = 1 ;
break ;
}
2002-12-12 23:55:49 +03:00
data = ( void * ) vg + _fields [ fp - > field_num ] . offset ;
break ;
case PVS :
data = ( void * ) pv + _fields [ fp - > field_num ] . offset ;
break ;
case SEGS :
data = ( void * ) seg + _fields [ fp - > field_num ] . offset ;
2005-04-20 00:58:25 +04:00
break ;
case PVSEGS :
data = ( void * ) pvseg + _fields [ fp - > field_num ] . offset ;
2002-12-12 23:55:49 +03:00
}
2004-06-19 23:27:00 +04:00
if ( skip ) {
field - > report_string = " " ;
field - > sort_value = ( const void * ) field - > report_string ;
} else if ( ! _fields [ fp - > field_num ] . report_fn ( rh , field , data ) ) {
2002-12-12 23:55:49 +03:00
log_error ( " report function failed for field %s " ,
_fields [ fp - > field_num ] . id ) ;
return 0 ;
}
if ( ( strlen ( field - > report_string ) > field - > props - > width ) )
field - > props - > width = strlen ( field - > report_string ) ;
if ( ( rh - > flags & RH_SORT_REQUIRED ) & &
( field - > props - > flags & FLD_SORT_KEY ) ) {
( * row - > sort_fields ) [ field - > props - > sort_posn ] = field ;
}
list_add ( & row - > fields , & field - > list ) ;
}
if ( ! ( rh - > flags & RH_BUFFERED ) )
report_output ( handle ) ;
return 1 ;
}
/*
* Print row of headings
*/
2002-12-20 02:25:55 +03:00
static int _report_headings ( void * handle )
2002-12-12 23:55:49 +03:00
{
struct report_handle * rh = handle ;
struct field_properties * fp ;
2004-05-05 22:23:11 +04:00
const char * heading ;
char buf [ 1024 ] ;
2002-12-12 23:55:49 +03:00
if ( rh - > flags & RH_HEADINGS_PRINTED )
return 1 ;
2004-05-05 22:23:11 +04:00
rh - > flags | = RH_HEADINGS_PRINTED ;
2002-12-12 23:55:49 +03:00
if ( ! ( rh - > flags & RH_HEADINGS ) )
2004-05-05 22:23:11 +04:00
return 1 ;
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_begin_object ( rh - > mem , 128 ) ) {
log_error ( " dm_pool_begin_object failed for headings " ) ;
2004-05-05 22:23:11 +04:00
return 0 ;
}
2002-12-12 23:55:49 +03:00
/* First heading line */
2005-06-01 20:51:55 +04:00
list_iterate_items ( fp , & rh - > field_props ) {
2002-12-12 23:55:49 +03:00
if ( fp - > flags & FLD_HIDDEN )
continue ;
2004-05-05 22:23:11 +04:00
heading = _fields [ fp - > field_num ] . heading ;
if ( rh - > flags & RH_ALIGNED ) {
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( buf , sizeof ( buf ) , " %-*.*s " ,
2004-05-05 22:23:11 +04:00
fp - > width , fp - > width , heading ) < 0 ) {
log_error ( " snprintf heading failed " ) ;
2005-10-17 03:03:59 +04:00
dm_pool_end_object ( rh - > mem ) ;
2004-05-05 22:23:11 +04:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , buf , fp - > width ) )
2004-05-05 22:23:11 +04:00
goto bad ;
2005-10-17 03:03:59 +04:00
} else if ( ! dm_pool_grow_object ( rh - > mem , heading , strlen ( heading ) ) )
2004-05-05 22:23:11 +04:00
goto bad ;
2005-06-01 20:51:55 +04:00
if ( ! list_end ( & rh - > field_props , & fp - > list ) )
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , rh - > separator ,
2004-05-05 22:23:11 +04:00
strlen ( rh - > separator ) ) )
goto bad ;
2002-12-12 23:55:49 +03:00
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed " ) ;
2004-05-05 22:23:11 +04:00
goto bad ;
}
2005-10-17 03:03:59 +04:00
log_print ( " %s " , ( char * ) dm_pool_end_object ( rh - > mem ) ) ;
2002-12-12 23:55:49 +03:00
return 1 ;
2004-05-05 22:23:11 +04:00
bad :
log_error ( " Failed to generate report headings for printing " ) ;
return 0 ;
2002-12-12 23:55:49 +03:00
}
/*
* Sort rows of data
*/
static int _row_compare ( const void * a , const void * b )
{
2002-12-20 02:25:55 +03:00
const struct row * rowa = * ( const struct row * * ) a ;
const struct row * rowb = * ( const struct row * * ) b ;
const struct field * sfa , * sfb ;
2002-12-12 23:55:49 +03:00
int32_t cnt = - 1 ;
for ( cnt = 0 ; cnt < rowa - > rh - > keys_count ; cnt + + ) {
sfa = ( * rowa - > sort_fields ) [ cnt ] ;
sfb = ( * rowb - > sort_fields ) [ cnt ] ;
if ( sfa - > props - > flags & FLD_NUMBER ) {
2002-12-20 02:25:55 +03:00
const uint64_t numa =
* ( const uint64_t * ) sfa - > sort_value ;
const uint64_t numb =
* ( const uint64_t * ) sfb - > sort_value ;
2002-12-12 23:55:49 +03:00
if ( numa = = numb )
continue ;
if ( sfa - > props - > flags & FLD_ASCENDING ) {
return ( numa > numb ) ? 1 : - 1 ;
} else { /* FLD_DESCENDING */
return ( numa < numb ) ? 1 : - 1 ;
}
} else { /* FLD_STRING */
2002-12-20 02:25:55 +03:00
const char * stra = ( const char * ) sfa - > sort_value ;
const char * strb = ( const char * ) sfb - > sort_value ;
2002-12-12 23:55:49 +03:00
int cmp = strcmp ( stra , strb ) ;
if ( ! cmp )
continue ;
if ( sfa - > props - > flags & FLD_ASCENDING ) {
return ( cmp > 0 ) ? 1 : - 1 ;
} else { /* FLD_DESCENDING */
return ( cmp < 0 ) ? 1 : - 1 ;
}
}
}
return 0 ; /* Identical */
}
static int _sort_rows ( struct report_handle * rh )
{
struct row * ( * rows ) [ ] ;
uint32_t count = 0 ;
struct row * row ;
2005-10-17 03:03:59 +04:00
if ( ! ( rows = dm_pool_alloc ( rh - > mem , sizeof ( * * rows ) *
2002-12-12 23:55:49 +03:00
list_size ( & rh - > rows ) ) ) ) {
log_error ( " sort array allocation failed " ) ;
return 0 ;
}
2005-06-01 20:51:55 +04:00
list_iterate_items ( row , & rh - > rows )
2002-12-12 23:55:49 +03:00
( * rows ) [ count + + ] = row ;
qsort ( rows , count , sizeof ( * * rows ) , _row_compare ) ;
list_init ( & rh - > rows ) ;
while ( count - - )
list_add_h ( & rh - > rows , & ( * rows ) [ count ] - > list ) ;
return 1 ;
}
/*
* Produce report output
*/
int report_output ( void * handle )
{
struct report_handle * rh = handle ;
struct list * fh , * rowh , * ftmp , * rtmp ;
struct row * row = NULL ;
struct field * field ;
2004-05-05 22:23:11 +04:00
const char * repstr ;
char buf [ 4096 ] ;
int width ;
2002-12-12 23:55:49 +03:00
if ( list_empty ( & rh - > rows ) )
return 1 ;
/* Sort rows */
if ( ( rh - > flags & RH_SORT_REQUIRED ) )
_sort_rows ( rh ) ;
/* If headings not printed yet, calculate field widths and print them */
if ( ! ( rh - > flags & RH_HEADINGS_PRINTED ) )
2002-12-20 02:25:55 +03:00
_report_headings ( rh ) ;
2002-12-12 23:55:49 +03:00
/* Print and clear buffer */
list_iterate_safe ( rowh , rtmp , & rh - > rows ) {
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_begin_object ( rh - > mem , 512 ) ) {
log_error ( " dm_pool_begin_object failed for row " ) ;
2004-05-05 22:23:11 +04:00
return 0 ;
}
2002-12-12 23:55:49 +03:00
row = list_item ( rowh , struct row ) ;
list_iterate_safe ( fh , ftmp , & row - > fields ) {
field = list_item ( fh , struct field ) ;
if ( field - > props - > flags & FLD_HIDDEN )
continue ;
2004-05-05 22:23:11 +04:00
repstr = field - > report_string ;
width = field - > props - > width ;
if ( ! ( rh - > flags & RH_ALIGNED ) ) {
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , repstr ,
2004-05-05 22:23:11 +04:00
strlen ( repstr ) ) )
goto bad ;
} else if ( field - > props - > flags & FLD_ALIGN_LEFT ) {
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( buf , sizeof ( buf ) , " %-*.*s " ,
2004-05-05 22:23:11 +04:00
width , width , repstr ) < 0 ) {
log_error ( " snprintf repstr failed " ) ;
2005-10-17 03:03:59 +04:00
dm_pool_end_object ( rh - > mem ) ;
2004-05-05 22:23:11 +04:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , buf , width ) )
2004-05-05 22:23:11 +04:00
goto bad ;
} else if ( field - > props - > flags & FLD_ALIGN_RIGHT ) {
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( buf , sizeof ( buf ) , " %*.*s " ,
2004-05-05 22:23:11 +04:00
width , width , repstr ) < 0 ) {
log_error ( " snprintf repstr failed " ) ;
2005-10-17 03:03:59 +04:00
dm_pool_end_object ( rh - > mem ) ;
2004-05-05 22:23:11 +04:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , buf , width ) )
2004-05-05 22:23:11 +04:00
goto bad ;
}
2002-12-12 23:55:49 +03:00
if ( ! list_end ( & row - > fields , fh ) )
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , rh - > separator ,
2004-05-05 22:23:11 +04:00
strlen ( rh - > separator ) ) )
goto bad ;
2002-12-12 23:55:49 +03:00
list_del ( & field - > list ) ;
}
2005-10-17 03:03:59 +04:00
if ( ! dm_pool_grow_object ( rh - > mem , " \0 " , 1 ) ) {
log_error ( " dm_pool_grow_object failed for row " ) ;
2004-05-05 22:23:11 +04:00
return 0 ;
}
2005-10-17 03:03:59 +04:00
log_print ( " %s " , ( char * ) dm_pool_end_object ( rh - > mem ) ) ;
2002-12-12 23:55:49 +03:00
list_del ( & row - > list ) ;
}
if ( row )
2005-10-17 03:03:59 +04:00
dm_pool_free ( rh - > mem , row ) ;
2002-12-12 23:55:49 +03:00
return 1 ;
2004-05-05 22:23:11 +04:00
bad :
log_error ( " Failed to generate row for printing " ) ;
return 0 ;
2002-12-12 23:55:49 +03:00
}