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
*/
2011-06-14 06:34:18 +04:00
# include <errno.h>
# include <stdio.h>
# include <string.h>
2011-08-31 16:18:40 +04:00
# include <unistd.h>
2012-02-28 22:35:04 +04:00
2012-08-11 12:33:53 +04:00
# include "dm-logging.h"
2012-09-26 16:44:03 +04:00
# include "config-util.h"
2012-02-28 22:35:04 +04:00
# include "libdevmapper.h"
2011-06-14 06:34:18 +04:00
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 ;
2012-09-09 23:57:59 +04:00
if ( strstr ( next , " %d " ) | | strstr ( next , " % " PRId64 ) ) {
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 ;
}
static void chain_node ( struct dm_config_node * cn ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
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 ;
}
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
2012-09-09 23:57:59 +04:00
if ( ! strcmp ( fmt , " %d " ) | | ! strcmp ( fmt , " % " PRId64 ) ) {
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 ;
}
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 ;
new = realloc ( buf - > mem , buf - > allocated ) ;
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 ;
}