2012-02-28 22:35:04 +04:00
/*
* Copyright ( C ) 2011 - 2012 Red Hat , Inc .
*
* 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
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser 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
*/
2015-07-06 19:30:18 +03:00
# define _REENTRANT
# include "tool.h"
2014-04-17 12:40:35 +04:00
# include "daemon-io.h"
# include "dm-logging.h"
2012-02-28 22:35:04 +04:00
2015-06-17 21:06:37 +03:00
# include <math.h> /* fabs() */
# include <float.h> /* DBL_EPSILON */
2012-10-11 16:17:17 +04:00
int buffer_append_vf ( struct buffer * buf , va_list ap )
2011-06-27 17:15:49 +04:00
{
2012-10-13 21:15:15 +04:00
char * append ;
2011-06-27 17:15:49 +04:00
char * next ;
2011-07-18 18:42:44 +04:00
int keylen ;
2012-10-12 12:57:01 +04:00
int64_t value ;
char * string ;
char * block ;
2011-06-27 17:15:49 +04:00
2011-08-31 16:18:40 +04:00
while ( ( next = va_arg ( ap , char * ) ) ) {
2012-10-13 21:15:15 +04:00
append = NULL ;
2012-08-11 12:33:53 +04:00
if ( ! strchr ( next , ' = ' ) ) {
log_error ( INTERNAL_ERROR " Bad format string at '%s' " , next ) ;
goto fail ;
}
2011-07-18 18:42:44 +04:00
keylen = strchr ( next , ' = ' ) - next ;
2015-07-06 17:09:17 +03:00
if ( strstr ( next , " %d " ) | | strstr ( next , FMTd64 ) ) {
2012-10-12 12:57:01 +04:00
value = va_arg ( ap , int64_t ) ;
2012-10-12 13:34:15 +04:00
if ( dm_asprintf ( & append , " %.*s= % " PRId64 " \n " , keylen , next , value ) < 0 )
2012-10-12 12:57:01 +04:00
goto fail ;
2011-07-18 18:42:44 +04:00
} else if ( strstr ( next , " %s " ) ) {
2012-10-12 12:57:01 +04:00
string = va_arg ( ap , char * ) ;
2012-10-12 13:34:15 +04:00
if ( dm_asprintf ( & append , " %.*s= \" %s \" \n " , keylen , next , string ) < 0 )
2012-10-12 12:57:01 +04:00
goto fail ;
2011-07-18 18:42:44 +04:00
} else if ( strstr ( next , " %b " ) ) {
2012-10-12 12:57:01 +04:00
if ( ! ( block = va_arg ( ap , char * ) ) )
2011-07-18 18:42:44 +04:00
continue ;
2012-10-12 13:34:15 +04:00
if ( dm_asprintf ( & append , " %.*s%s " , keylen , next , block ) < 0 )
2012-10-12 12:57:01 +04:00
goto fail ;
2012-10-12 13:34:15 +04:00
} else if ( dm_asprintf ( & append , " %s " , next ) < 0 )
2012-10-12 12:57:01 +04:00
goto fail ;
if ( ! append | |
! buffer_append ( buf , append ) )
2012-10-13 23:04:01 +04:00
goto fail ;
2012-10-12 12:57:01 +04:00
2012-10-11 16:17:17 +04:00
dm_free ( append ) ;
2011-06-27 17:15:49 +04:00
}
2012-10-11 16:17:17 +04:00
return 1 ;
2011-06-27 17:15:49 +04:00
fail :
2012-10-11 16:17:17 +04:00
dm_free ( append ) ;
return 0 ;
2011-06-27 17:15:49 +04:00
}
2012-08-11 12:33:53 +04:00
2012-10-11 16:17:17 +04:00
int buffer_append_f ( struct buffer * buf , . . . )
2012-08-11 12:33:53 +04:00
{
2012-10-12 12:15:30 +04:00
int res ;
2012-08-11 12:33:53 +04:00
va_list ap ;
2012-10-12 12:15:30 +04:00
2012-10-11 16:17:17 +04:00
va_start ( ap , buf ) ;
2012-10-12 12:15:30 +04:00
res = buffer_append_vf ( buf , ap ) ;
2012-08-11 12:33:53 +04:00
va_end ( ap ) ;
2012-10-12 12:15:30 +04:00
2012-08-11 12:33:53 +04:00
return res ;
}
int set_flag ( struct dm_config_tree * cft , struct dm_config_node * parent ,
const char * field , const char * flag , int want )
{
struct dm_config_value * value = NULL , * pred = NULL ;
struct dm_config_node * node = dm_config_find_node ( parent - > child , field ) ;
struct dm_config_value * new ;
if ( node )
value = node - > v ;
while ( value & & value - > type ! = DM_CFG_EMPTY_ARRAY & & strcmp ( value - > v . str , flag ) ) {
pred = value ;
value = value - > next ;
}
if ( value & & want )
return 1 ;
if ( ! value & & ! want )
return 1 ;
if ( value & & ! want ) {
if ( pred ) {
pred - > next = value - > next ;
} else if ( value = = node - > v & & value - > next ) {
node - > v = value - > next ;
} else {
node - > v - > type = DM_CFG_EMPTY_ARRAY ;
}
}
if ( ! value & & want ) {
if ( ! node ) {
if ( ! ( node = dm_config_create_node ( cft , field ) ) )
return 0 ;
node - > sib = parent - > child ;
if ( ! ( node - > v = dm_config_create_value ( cft ) ) )
return 0 ;
node - > v - > type = DM_CFG_EMPTY_ARRAY ;
node - > parent = parent ;
parent - > child = node ;
}
if ( ! ( new = dm_config_create_value ( cft ) ) ) {
/* FIXME error reporting */
return 0 ;
}
new - > type = DM_CFG_STRING ;
new - > v . str = flag ;
new - > next = node - > v ;
node - > v = new ;
}
return 1 ;
}
2015-03-31 22:50:29 +03:00
void chain_node ( struct dm_config_node * cn ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
2012-08-11 12:33:53 +04:00
{
cn - > parent = parent ;
cn - > sib = NULL ;
if ( parent & & parent - > child & & ! pre_sib ) { /* find the last one */
pre_sib = parent - > child ;
while ( pre_sib & & pre_sib - > sib )
pre_sib = pre_sib - > sib ;
}
if ( parent & & ! parent - > child )
parent - > child = cn ;
2012-08-13 21:44:10 +04:00
if ( pre_sib ) {
cn - > sib = pre_sib - > sib ;
2012-08-11 12:33:53 +04:00
pre_sib - > sib = cn ;
2012-08-13 21:44:10 +04:00
}
2012-08-11 12:33:53 +04:00
}
struct dm_config_node * make_config_node ( struct dm_config_tree * cft ,
const char * key ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
struct dm_config_node * cn ;
if ( ! ( cn = dm_config_create_node ( cft , key ) ) )
return NULL ;
cn - > v = NULL ;
cn - > child = NULL ;
chain_node ( cn , parent , pre_sib ) ;
return cn ;
}
struct dm_config_node * make_text_node ( struct dm_config_tree * cft ,
const char * key ,
const char * value ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
struct dm_config_node * cn ;
if ( ! ( cn = make_config_node ( cft , key , parent , pre_sib ) ) | |
! ( cn - > v = dm_config_create_value ( cft ) ) )
return NULL ;
cn - > v - > type = DM_CFG_STRING ;
cn - > v - > v . str = value ;
return cn ;
}
struct dm_config_node * make_int_node ( struct dm_config_tree * cft ,
const char * key ,
int64_t value ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
struct dm_config_node * cn ;
if ( ! ( cn = make_config_node ( cft , key , parent , pre_sib ) ) | |
! ( cn - > v = dm_config_create_value ( cft ) ) )
return NULL ;
cn - > v - > type = DM_CFG_INT ;
cn - > v - > v . i = value ;
return cn ;
}
2015-07-09 17:34:02 +03:00
/*
* FIXME : return 1 even if VA list is empty and return the
* dm_config_node * result as output parameter
*/
2012-08-11 12:33:53 +04:00
struct dm_config_node * config_make_nodes_v ( struct dm_config_tree * cft ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib ,
va_list ap )
{
const char * next ;
struct dm_config_node * first = NULL ;
2012-10-12 12:15:30 +04:00
struct dm_config_node * cn ;
2012-12-14 04:00:36 +04:00
const char * fmt ;
char * key ;
2012-08-11 12:33:53 +04:00
while ( ( next = va_arg ( ap , char * ) ) ) {
2012-10-12 12:15:30 +04:00
cn = NULL ;
fmt = strchr ( next , ' = ' ) ;
2012-08-11 12:33:53 +04:00
if ( ! fmt ) {
log_error ( INTERNAL_ERROR " Bad format string '%s' " , fmt ) ;
2012-12-14 04:00:36 +04:00
return NULL ;
}
if ( ! ( key = dm_pool_strdup ( cft - > mem , next ) ) ) {
log_error ( " Failed to duplicate node key. " ) ;
return NULL ;
2012-08-11 12:33:53 +04:00
}
2012-12-14 04:00:36 +04:00
key [ fmt - next ] = ' \0 ' ;
fmt + = 2 ;
2012-08-11 12:33:53 +04:00
2015-07-06 17:09:17 +03:00
if ( ! strcmp ( fmt , " %d " ) | | ! strcmp ( fmt , FMTd64 ) ) {
2012-08-11 12:33:53 +04:00
int64_t value = va_arg ( ap , int64_t ) ;
if ( ! ( cn = make_int_node ( cft , key , value , parent , pre_sib ) ) )
return 0 ;
} else if ( ! strcmp ( fmt , " %s " ) ) {
char * value = va_arg ( ap , char * ) ;
if ( ! ( cn = make_text_node ( cft , key , value , parent , pre_sib ) ) )
return 0 ;
} else if ( ! strcmp ( fmt , " %t " ) ) {
struct dm_config_tree * tree = va_arg ( ap , struct dm_config_tree * ) ;
cn = dm_config_clone_node ( cft , tree - > root , 1 ) ;
if ( ! cn )
return 0 ;
cn - > key = key ;
chain_node ( cn , parent , pre_sib ) ;
} else {
log_error ( INTERNAL_ERROR " Bad format string '%s' " , fmt ) ;
2012-12-14 04:00:36 +04:00
return NULL ;
2012-08-11 12:33:53 +04:00
}
if ( ! first )
first = cn ;
if ( cn )
pre_sib = cn ;
}
return first ;
}
struct dm_config_node * config_make_nodes ( struct dm_config_tree * cft ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib ,
. . . )
{
2012-10-12 12:15:30 +04:00
struct dm_config_node * res ;
2012-08-11 12:33:53 +04:00
va_list ap ;
2012-10-12 12:15:30 +04:00
2012-08-11 12:33:53 +04:00
va_start ( ap , pre_sib ) ;
2012-10-12 12:15:30 +04:00
res = config_make_nodes_v ( cft , parent , pre_sib , ap ) ;
2012-08-11 12:33:53 +04:00
va_end ( ap ) ;
2012-10-12 12:15:30 +04:00
2012-08-11 12:33:53 +04:00
return res ;
}
2015-06-17 21:06:37 +03:00
/* Test if the doubles are close enough to be considered equal */
static int close_enough ( double d1 , double d2 )
{
return fabs ( d1 - d2 ) < DBL_EPSILON ;
}
2015-09-29 21:40:52 +03:00
int compare_value ( struct dm_config_value * a , struct dm_config_value * b )
2015-06-17 21:06:37 +03:00
{
int r = 0 ;
if ( a - > type > b - > type )
return 1 ;
if ( a - > type < b - > type )
return - 1 ;
switch ( a - > type ) {
case DM_CFG_STRING : r = strcmp ( a - > v . str , b - > v . str ) ; break ;
case DM_CFG_FLOAT : r = close_enough ( a - > v . f , b - > v . f ) ? 0 : ( a - > v . f > b - > v . f ) ? 1 : - 1 ; break ;
case DM_CFG_INT : r = ( a - > v . i = = b - > v . i ) ? 0 : ( a - > v . i > b - > v . i ) ? 1 : - 1 ; break ;
case DM_CFG_EMPTY_ARRAY : return 0 ;
}
if ( r = = 0 & & a - > next & & b - > next )
r = compare_value ( a - > next , b - > next ) ;
return r ;
}
int compare_config ( struct dm_config_node * a , struct dm_config_node * b )
{
int result = 0 ;
if ( a - > v & & b - > v )
result = compare_value ( a - > v , b - > v ) ;
if ( a - > v & & ! b - > v )
result = 1 ;
if ( ! a - > v & & b - > v )
result = - 1 ;
if ( a - > child & & b - > child )
result = compare_config ( a - > child , b - > child ) ;
if ( result ) {
// DEBUGLOG("config inequality at %s / %s", a->key, b->key);
return result ;
}
if ( a - > sib & & b - > sib )
result = compare_config ( a - > sib , b - > sib ) ;
if ( a - > sib & & ! b - > sib )
result = 1 ;
if ( ! a - > sib & & b - > sib )
result = - 1 ;
return result ;
}
2012-10-11 16:17:17 +04:00
int buffer_realloc ( struct buffer * buf , int needed )
2012-08-11 12:33:53 +04:00
{
2012-10-11 16:17:17 +04:00
char * new ;
int alloc = buf - > allocated ;
if ( alloc < needed )
alloc = needed ;
buf - > allocated + = alloc ;
2013-06-18 23:57:14 +04:00
new = dm_realloc ( buf - > mem , buf - > allocated ) ;
2012-10-11 16:17:17 +04:00
if ( new )
buf - > mem = new ;
else { /* utter failure */
dm_free ( buf - > mem ) ;
buf - > mem = 0 ;
buf - > allocated = buf - > used = 0 ;
return 0 ;
}
return 1 ;
}
int buffer_append ( struct buffer * buf , const char * string )
{
int len = strlen ( string ) ;
2012-08-11 12:33:53 +04:00
2012-10-12 12:50:07 +04:00
if ( ( buf - > allocated - buf - > used < = len ) & &
! buffer_realloc ( buf , len + 1 ) )
return 0 ;
2012-08-11 12:33:53 +04:00
2012-10-11 16:17:17 +04:00
strcpy ( buf - > mem + buf - > used , string ) ;
buf - > used + = len ;
return 1 ;
2012-08-11 12:33:53 +04:00
}
int buffer_line ( const char * line , void * baton )
{
2012-10-11 16:17:17 +04:00
struct buffer * buf = baton ;
if ( ! buffer_append ( buf , line ) )
return 0 ;
if ( ! buffer_append ( buf , " \n " ) )
2012-08-11 12:33:53 +04:00
return 0 ;
return 1 ;
}
2012-10-11 16:17:17 +04:00
void buffer_destroy ( struct buffer * buf )
{
dm_free ( buf - > mem ) ;
buffer_init ( buf ) ;
}
void buffer_init ( struct buffer * buf )
{
buf - > allocated = buf - > used = 0 ;
buf - > mem = 0 ;
}