2001-08-21 12:56:08 +00:00
/*
2007-07-08 22:51:20 +00:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2011-05-24 13:53:26 +00:00
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
2001-08-21 12:56:08 +00:00
*
2004-03-30 19:35:44 +00:00
* 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
2007-08-20 20:55:30 +00:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 19:35:44 +00:00
*
2007-08-20 20:55:30 +00:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 19:35:44 +00:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-08-21 12:56:08 +00:00
*/
2011-08-30 14:55:15 +00:00
2002-11-18 14:01:16 +00:00
# include "lib.h"
2011-08-30 14:55:15 +00:00
2002-11-18 14:01:16 +00:00
# include "config.h"
# include "crc.h"
# include "device.h"
2004-05-04 18:28:15 +00:00
# include "str_list.h"
# include "toolcontext.h"
2007-07-24 17:48:08 +00:00
# include "lvm-file.h"
2013-06-25 12:27:04 +02:00
# include "memlock.h"
2002-11-18 14:01:16 +00:00
2001-08-21 12:56:08 +00:00
# include <sys/stat.h>
# include <sys/mman.h>
# include <unistd.h>
# include <fcntl.h>
2011-12-18 21:56:03 +00:00
# include <assert.h>
2013-03-05 17:36:10 +01:00
# include <ctype.h>
2001-09-13 12:38:31 +00:00
2013-06-25 12:25:43 +02:00
static const char * _config_source_names [ ] = {
[ CONFIG_UNDEFINED ] = " undefined " ,
[ CONFIG_FILE ] = " file " ,
[ CONFIG_MERGED_FILES ] = " merged files " ,
[ CONFIG_STRING ] = " string " ,
[ CONFIG_PROFILE ] = " profile "
} ;
2011-12-18 21:56:03 +00:00
struct config_file {
off_t st_size ;
char * filename ;
int exists ;
int keep_open ;
struct device * dev ;
} ;
2013-06-25 12:25:43 +02:00
struct config_source {
config_source_t type ;
time_t timestamp ;
union {
struct config_file * file ;
struct config_file * profile ;
} source ;
} ;
2013-03-05 16:49:42 +01:00
static char _cfg_path [ CFG_PATH_MAX_LEN ] ;
/*
* Map each ID to respective definition of the configuration item .
*/
static struct cfg_def_item _cfg_def_items [ CFG_COUNT + 1 ] = {
# define cfg_section(id, name, parent, flags, since_version, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, comment},
# define cfg(id, name, parent, flags, type, default_value, since_version, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, comment},
# define cfg_array(id, name, parent, flags, types, default_value, since_version, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, comment},
# include "config_settings.h"
# undef cfg_section
# undef cfg
# undef cfg_array
} ;
2013-06-25 12:25:43 +02:00
config_source_t config_get_source_type ( struct dm_config_tree * cft )
{
struct config_source * cs = dm_config_get_custom ( cft ) ;
return cs ? cs - > type : CONFIG_UNDEFINED ;
}
2011-12-18 21:56:03 +00:00
/*
* public interface
*/
2013-06-25 12:25:43 +02:00
struct dm_config_tree * config_open ( config_source_t source ,
const char * filename ,
int keep_open )
2002-01-07 10:23:52 +00:00
{
2011-12-18 21:56:03 +00:00
struct dm_config_tree * cft = dm_config_create ( ) ;
2013-06-25 12:25:43 +02:00
struct config_source * cs ;
2011-12-18 21:56:03 +00:00
struct config_file * cf ;
2013-06-25 12:25:43 +02:00
2011-12-18 21:56:03 +00:00
if ( ! cft )
return NULL ;
2013-06-25 12:25:43 +02:00
if ( ! ( cs = dm_pool_zalloc ( cft - > mem , sizeof ( struct config_source ) ) ) ) {
log_error ( " Failed to allocate config source. " ) ;
2013-04-23 11:58:50 +02:00
goto fail ;
}
2002-01-07 10:23:52 +00:00
2013-06-25 12:25:43 +02:00
if ( ( source = = CONFIG_FILE ) | | ( source = = CONFIG_PROFILE ) ) {
if ( ! ( cf = dm_pool_zalloc ( cft - > mem , sizeof ( struct config_file ) ) ) ) {
log_error ( " Failed to allocate config file. " ) ;
goto fail ;
}
2011-12-18 21:56:03 +00:00
2013-06-25 12:25:43 +02:00
cf - > keep_open = keep_open ;
if ( filename & &
! ( cf - > filename = dm_pool_strdup ( cft - > mem , filename ) ) ) {
log_error ( " Failed to duplicate filename. " ) ;
goto fail ;
}
cs - > source . file = cf ;
2011-12-18 21:56:03 +00:00
}
2013-06-25 12:25:43 +02:00
cs - > type = source ;
dm_config_set_custom ( cft , cs ) ;
2011-12-18 21:56:03 +00:00
return cft ;
fail :
dm_config_destroy ( cft ) ;
return NULL ;
}
/*
* Doesn ' t populate filename if the file is empty .
*/
int config_file_check ( struct dm_config_tree * cft , const char * * filename , struct stat * info )
{
2013-06-25 12:25:43 +02:00
struct config_source * cs = dm_config_get_custom ( cft ) ;
struct config_file * cf ;
2011-12-18 21:56:03 +00:00
struct stat _info ;
2013-06-25 12:25:43 +02:00
if ( ( cs - > type ! = CONFIG_FILE ) & & ( cs - > type ! = CONFIG_PROFILE ) ) {
log_error ( INTERNAL_ERROR " config_file_check: expected file or profile config source, "
" found %s config source. " , _config_source_names [ cs - > type ] ) ;
return 0 ;
}
2011-12-18 21:56:03 +00:00
if ( ! info )
info = & _info ;
2013-06-25 12:25:43 +02:00
cf = cs - > source . file ;
2011-12-18 21:56:03 +00:00
if ( stat ( cf - > filename , info ) ) {
log_sys_error ( " stat " , cf - > filename ) ;
cf - > exists = 0 ;
return 0 ;
}
if ( ! S_ISREG ( info - > st_mode ) ) {
log_error ( " %s is not a regular file " , cf - > filename ) ;
cf - > exists = 0 ;
return 0 ;
}
2013-06-25 12:25:43 +02:00
cs - > timestamp = info - > st_ctime ;
2011-12-18 21:56:03 +00:00
cf - > exists = 1 ;
cf - > st_size = info - > st_size ;
if ( info - > st_size = = 0 )
log_verbose ( " %s is empty " , cf - > filename ) ;
else if ( filename )
* filename = cf - > filename ;
return 1 ;
}
/*
* Return 1 if config files ought to be reloaded
*/
int config_file_changed ( struct dm_config_tree * cft )
{
2013-06-25 12:25:43 +02:00
struct config_source * cs = dm_config_get_custom ( cft ) ;
struct config_file * cf ;
2011-12-18 21:56:03 +00:00
struct stat info ;
2013-06-25 12:25:43 +02:00
if ( cs - > type ! = CONFIG_FILE ) {
log_error ( INTERNAL_ERROR " config_file_changed: expected file config source, "
" found %s config source. " , _config_source_names [ cs - > type ] ) ;
return 0 ;
}
cf = cs - > source . file ;
2011-12-18 21:56:03 +00:00
if ( ! cf - > filename )
return 0 ;
if ( stat ( cf - > filename , & info ) = = - 1 ) {
/* Ignore a deleted config file: still use original data */
if ( errno = = ENOENT ) {
if ( ! cf - > exists )
return 0 ;
log_very_verbose ( " Config file %s has disappeared! " ,
cf - > filename ) ;
goto reload ;
}
log_sys_error ( " stat " , cf - > filename ) ;
log_error ( " Failed to reload configuration files " ) ;
return 0 ;
}
if ( ! S_ISREG ( info . st_mode ) ) {
log_error ( " Configuration file %s is not a regular file " ,
cf - > filename ) ;
goto reload ;
}
/* Unchanged? */
2013-06-25 12:25:43 +02:00
if ( cs - > timestamp = = info . st_ctime & & cf - > st_size = = info . st_size )
2011-12-18 21:56:03 +00:00
return 0 ;
reload :
log_verbose ( " Detected config file change to %s " , cf - > filename ) ;
return 1 ;
}
2013-06-25 12:25:43 +02:00
void config_destroy ( struct dm_config_tree * cft )
2011-12-18 21:56:03 +00:00
{
2013-06-25 12:25:43 +02:00
struct config_source * cs ;
struct config_file * cf ;
2011-12-18 21:56:03 +00:00
2013-06-25 12:25:43 +02:00
if ( ! cft )
return ;
cs = dm_config_get_custom ( cft ) ;
if ( ( cs - > type = = CONFIG_FILE ) | | ( cs - > type = = CONFIG_PROFILE ) ) {
cf = cs - > source . file ;
if ( cf & & cf - > dev )
if ( ! dev_close ( cf - > dev ) )
stack ;
}
2002-01-07 10:23:52 +00:00
2011-08-30 14:55:15 +00:00
dm_config_destroy ( cft ) ;
2006-05-16 16:48:31 +00:00
}
2013-06-25 12:25:43 +02:00
struct dm_config_tree * config_file_open_and_read ( const char * config_file ,
config_source_t source )
2013-06-25 12:25:23 +02:00
{
struct dm_config_tree * cft ;
struct stat info ;
2013-06-25 12:25:43 +02:00
if ( ! ( cft = config_open ( source , config_file , 0 ) ) ) {
2013-06-25 12:25:23 +02:00
log_error ( " config_tree allocation failed " ) ;
return NULL ;
}
/* Is there a config file? */
if ( stat ( config_file , & info ) = = - 1 ) {
2013-06-25 12:25:43 +02:00
/* Profile file must be present! */
if ( errno = = ENOENT & & ( source ! = CONFIG_PROFILE ) )
2013-06-25 12:25:23 +02:00
return cft ;
log_sys_error ( " stat " , config_file ) ;
goto bad ;
}
log_very_verbose ( " Loading config file: %s " , config_file ) ;
if ( ! config_file_read ( cft ) ) {
log_error ( " Failed to load config file %s " , config_file ) ;
goto bad ;
}
return cft ;
bad :
2013-06-25 12:25:43 +02:00
config_destroy ( cft ) ;
2013-06-25 12:25:23 +02:00
return NULL ;
}
2011-09-02 01:32:08 +00:00
/*
* Returns config tree if it was removed .
*/
2013-06-25 12:25:43 +02:00
struct dm_config_tree * remove_config_tree_by_source ( struct cmd_context * cmd ,
config_source_t source )
2011-09-02 01:32:08 +00:00
{
2013-06-25 12:25:43 +02:00
struct dm_config_tree * previous_cft = NULL ;
struct dm_config_tree * cft = cmd - > cft ;
struct config_source * cs ;
while ( cft ) {
cs = dm_config_get_custom ( cft ) ;
if ( cs & & ( cs - > type = = source ) ) {
if ( previous_cft ) {
previous_cft - > cascade = cft - > cascade ;
cmd - > cft = previous_cft ;
} else
cmd - > cft = cft - > cascade ;
cft - > cascade = NULL ;
break ;
}
previous_cft = cft ;
cft = cft - > cascade ;
}
2011-09-02 01:32:08 +00:00
2013-06-25 12:25:43 +02:00
return cft ;
2011-09-02 01:32:08 +00:00
}
2009-07-27 21:01:56 +00:00
int override_config_tree_from_string ( struct cmd_context * cmd ,
const char * config_settings )
{
2011-09-02 01:32:08 +00:00
struct dm_config_tree * cft_new ;
2013-06-25 12:25:43 +02:00
struct config_source * cs = dm_config_get_custom ( cmd - > cft ) ;
/*
* Follow this sequence :
* CONFIG_STRING - > CONFIG_FILE / CONFIG_MERGED_FILES
*/
if ( cs - > type = = CONFIG_STRING ) {
log_error ( INTERNAL_ERROR " override_config_tree_from_string: "
" config cascade already contains a string config. " ) ;
return 0 ;
}
2011-09-02 01:32:08 +00:00
if ( ! ( cft_new = dm_config_from_string ( config_settings ) ) ) {
2009-07-27 21:01:56 +00:00
log_error ( " Failed to set overridden configuration entries. " ) ;
2012-10-16 10:07:27 +02:00
return 0 ;
2009-07-27 21:01:56 +00:00
}
2013-06-25 12:25:43 +02:00
if ( ! ( cs = dm_pool_zalloc ( cft_new - > mem , sizeof ( struct config_source ) ) ) ) {
log_error ( " Failed to allocate config source. " ) ;
dm_config_destroy ( cft_new ) ;
return 0 ;
}
cs - > type = CONFIG_STRING ;
dm_config_set_custom ( cft_new , cs ) ;
2011-09-02 01:32:08 +00:00
cmd - > cft = dm_config_insert_cascaded_tree ( cft_new , cmd - > cft ) ;
2012-10-16 10:07:27 +02:00
return 1 ;
2009-07-27 21:01:56 +00:00
}
2011-12-18 21:56:03 +00:00
int config_file_read_fd ( struct dm_config_tree * cft , struct device * dev ,
off_t offset , size_t size , off_t offset2 , size_t size2 ,
checksum_fn_t checksum_fn , uint32_t checksum )
2001-08-21 12:56:08 +00:00
{
2012-02-23 22:36:21 +00:00
char * fb , * fe ;
2002-11-18 14:01:16 +00:00
int r = 0 ;
2003-07-04 22:34:56 +00:00
int use_mmap = 1 ;
off_t mmap_offset = 0 ;
2007-06-13 15:11:19 +00:00
char * buf = NULL ;
2013-06-25 12:25:43 +02:00
struct config_source * cs = dm_config_get_custom ( cft ) ;
if ( ( cs - > type ! = CONFIG_FILE ) & & ( cs - > type ! = CONFIG_PROFILE ) ) {
log_error ( INTERNAL_ERROR " config_file_read_fd: expected file or profile config source, "
" found %s config source. " , _config_source_names [ cs - > type ] ) ;
return 0 ;
}
2002-04-24 18:20:51 +00:00
2003-07-04 22:34:56 +00:00
/* Only use mmap with regular files */
if ( ! ( dev - > flags & DEV_REGULAR ) | | size2 )
use_mmap = 0 ;
if ( use_mmap ) {
2006-08-17 18:23:44 +00:00
mmap_offset = offset % lvm_getpagesize ( ) ;
2002-11-18 14:01:16 +00:00
/* memory map the file */
2011-08-30 14:55:15 +00:00
fb = mmap ( ( caddr_t ) 0 , size + mmap_offset , PROT_READ ,
MAP_PRIVATE , dev_fd ( dev ) , offset - mmap_offset ) ;
if ( fb = = ( caddr_t ) ( - 1 ) ) {
2003-07-04 22:34:56 +00:00
log_sys_error ( " mmap " , dev_name ( dev ) ) ;
2002-11-18 14:01:16 +00:00
goto out ;
}
2011-08-30 14:55:15 +00:00
fb = fb + mmap_offset ;
2003-07-04 22:34:56 +00:00
} else {
2011-10-11 09:06:09 +00:00
if ( ! ( buf = dm_malloc ( size + size2 ) ) ) {
log_error ( " Failed to allocate circular buffer. " ) ;
return 0 ;
}
2007-04-19 02:10:42 +00:00
if ( ! dev_read_circular ( dev , ( uint64_t ) offset , size ,
( uint64_t ) offset2 , size2 , buf ) ) {
2003-07-04 22:34:56 +00:00
goto out ;
}
2011-08-30 14:55:15 +00:00
fb = buf ;
2002-11-18 14:01:16 +00:00
}
if ( checksum_fn & & checksum ! =
2011-08-30 14:55:15 +00:00
( checksum_fn ( checksum_fn ( INITIAL_CRC , ( const uint8_t * ) fb , size ) ,
( const uint8_t * ) ( fb + size ) , size2 ) ) ) {
2003-07-04 22:34:56 +00:00
log_error ( " %s: Checksum error " , dev_name ( dev ) ) ;
2002-11-18 14:01:16 +00:00
goto out ;
}
2011-08-30 14:55:15 +00:00
fe = fb + size + size2 ;
if ( ! dm_config_parse ( cft , fb , fe ) )
2008-01-30 13:19:47 +00:00
goto_out ;
2002-11-18 14:01:16 +00:00
r = 1 ;
out :
2003-07-04 22:34:56 +00:00
if ( ! use_mmap )
2006-05-16 16:48:31 +00:00
dm_free ( buf ) ;
2002-11-18 14:01:16 +00:00
else {
/* unmap the file */
2012-02-23 22:36:21 +00:00
if ( munmap ( fb - mmap_offset , size + mmap_offset ) ) {
2003-07-04 22:34:56 +00:00
log_sys_error ( " munmap " , dev_name ( dev ) ) ;
2002-11-18 14:01:16 +00:00
r = 0 ;
}
}
return r ;
}
2011-12-18 21:56:03 +00:00
int config_file_read ( struct dm_config_tree * cft )
2002-11-18 14:01:16 +00:00
{
2011-09-02 01:32:08 +00:00
const char * filename = NULL ;
2013-06-25 12:25:43 +02:00
struct config_source * cs = dm_config_get_custom ( cft ) ;
struct config_file * cf ;
2002-11-18 14:01:16 +00:00
struct stat info ;
2011-08-30 14:55:15 +00:00
int r ;
2002-04-24 18:20:51 +00:00
2011-12-18 21:56:03 +00:00
if ( ! config_file_check ( cft , & filename , & info ) )
2011-09-01 21:04:14 +00:00
return_0 ;
2004-05-04 18:28:15 +00:00
2011-09-02 01:32:08 +00:00
/* Nothing to do. E.g. empty file. */
if ( ! filename )
return 1 ;
2013-06-25 12:25:43 +02:00
cf = cs - > source . file ;
2011-12-18 21:56:03 +00:00
if ( ! cf - > dev ) {
if ( ! ( cf - > dev = dev_create_file ( filename , NULL , NULL , 1 ) ) )
2006-11-04 03:34:10 +00:00
return_0 ;
2003-07-04 22:34:56 +00:00
2011-12-18 21:56:03 +00:00
if ( ! dev_open_readonly_buffered ( cf - > dev ) )
2006-11-04 03:34:10 +00:00
return_0 ;
2002-04-24 18:20:51 +00:00
}
2011-12-18 21:56:03 +00:00
r = config_file_read_fd ( cft , cf - > dev , 0 , ( size_t ) info . st_size , 0 , 0 ,
( checksum_fn_t ) NULL , 0 ) ;
2002-11-18 14:01:16 +00:00
2011-12-18 21:56:03 +00:00
if ( ! cf - > keep_open ) {
2012-03-01 21:12:37 +00:00
if ( ! dev_close ( cf - > dev ) )
stack ;
2011-12-18 21:56:03 +00:00
cf - > dev = NULL ;
2006-11-04 03:34:10 +00:00
}
2002-11-18 14:01:16 +00:00
return r ;
}
2011-12-18 21:56:03 +00:00
time_t config_file_timestamp ( struct dm_config_tree * cft )
{
2013-06-25 12:25:43 +02:00
struct config_source * cs = dm_config_get_custom ( cft ) ;
return cs - > timestamp ;
2011-12-18 21:56:03 +00:00
}
2013-03-05 16:49:42 +01:00
# define cfg_def_get_item_p(id) (&_cfg_def_items[id])
# define cfg_def_get_default_value(item,type) item->default_value.v_##type
# define cfg_def_get_path(item) (_cfg_def_make_path(_cfg_path,CFG_PATH_MAX_LEN,item->id,item),_cfg_path)
static int _cfg_def_make_path ( char * buf , size_t buf_size , int id , cfg_def_item_t * item )
{
int parent_id = item - > parent ;
int count , n ;
if ( id = = parent_id )
return 0 ;
count = _cfg_def_make_path ( buf , buf_size , parent_id , cfg_def_get_item_p ( parent_id ) ) ;
if ( ( n = dm_snprintf ( buf + count , buf_size - count , " %s%s " ,
count ? " / " : " " ,
item - > flags & CFG_NAME_VARIABLE ? " # " : item - > name ) ) < 0 ) {
log_error ( INTERNAL_ERROR " _cfg_def_make_path: supplied buffer too small for %s/%s " ,
cfg_def_get_item_p ( parent_id ) - > name , item - > name ) ;
buf [ 0 ] = ' \0 ' ;
return 0 ;
}
return count + n ;
}
int config_def_get_path ( char * buf , size_t buf_size , int id )
{
return _cfg_def_make_path ( buf , buf_size , id , cfg_def_get_item_p ( id ) ) ;
}
2013-03-05 17:14:18 +01:00
static void _get_type_name ( char * buf , size_t buf_size , cfg_def_type_t type )
{
2013-04-19 21:24:51 +02:00
( void ) dm_snprintf ( buf , buf_size , " %s%s%s%s%s%s " ,
( type & CFG_TYPE_ARRAY ) ?
( ( type & ~ CFG_TYPE_ARRAY ) ?
" array with values of type: " : " array " ) : " " ,
( type & CFG_TYPE_SECTION ) ? " section " : " " ,
( type & CFG_TYPE_BOOL ) ? " boolean " : " " ,
( type & CFG_TYPE_INT ) ? " integer " : " " ,
( type & CFG_TYPE_FLOAT ) ? " float " : " " ,
( type & CFG_TYPE_STRING ) ? " string " : " " ) ;
2013-03-05 17:14:18 +01:00
}
static void _log_type_error ( const char * path , cfg_def_type_t actual ,
cfg_def_type_t expected , int suppress_messages )
{
2013-04-19 21:24:51 +02:00
static char actual_type_name [ 128 ] ;
static char expected_type_name [ 128 ] ;
2013-03-05 17:14:18 +01:00
_get_type_name ( actual_type_name , sizeof ( actual_type_name ) , actual ) ;
_get_type_name ( expected_type_name , sizeof ( expected_type_name ) , expected ) ;
log_warn_suppress ( suppress_messages , " Configuration setting \" %s \" has invalid type. "
" Found%s, expected%s. " , path ,
actual_type_name , expected_type_name ) ;
}
static int _config_def_check_node_single_value ( const char * rp , const struct dm_config_value * v ,
const cfg_def_item_t * def , int suppress_messages )
{
/* Check empty array first if present. */
if ( v - > type = = DM_CFG_EMPTY_ARRAY ) {
if ( ! ( def - > type & CFG_TYPE_ARRAY ) ) {
_log_type_error ( rp , CFG_TYPE_ARRAY , def - > type , suppress_messages ) ;
return 0 ;
}
if ( ! ( def - > flags & CFG_ALLOW_EMPTY ) ) {
log_warn_suppress ( suppress_messages ,
" Configuration setting \" %s \" invalid. Empty value not allowed. " , rp ) ;
return 0 ;
}
return 1 ;
}
switch ( v - > type ) {
case DM_CFG_INT :
if ( ! ( def - > type & CFG_TYPE_INT ) & & ! ( def - > type & CFG_TYPE_BOOL ) ) {
_log_type_error ( rp , CFG_TYPE_INT , def - > type , suppress_messages ) ;
return 0 ;
}
break ;
case DM_CFG_FLOAT :
if ( ! ( def - > type & CFG_TYPE_FLOAT ) ) {
_log_type_error ( rp , CFG_TYPE_FLOAT , def - > type , suppress_messages ) ;
return 0 ;
}
break ;
case DM_CFG_STRING :
if ( def - > type & CFG_TYPE_BOOL ) {
if ( ! dm_config_value_is_bool ( v ) ) {
log_warn_suppress ( suppress_messages ,
" Configuration setting \" %s \" invalid. "
" Found string value \" %s \" , "
" expected boolean value: 0/1, \" y/n \" , "
" \" yes/no \" , \" on/off \" , "
" \" true/false \" . " , rp , v - > v . str ) ;
return 0 ;
}
} else if ( ! ( def - > type & CFG_TYPE_STRING ) ) {
_log_type_error ( rp , CFG_TYPE_STRING , def - > type , suppress_messages ) ;
return 0 ;
}
break ;
default : ;
}
return 1 ;
}
static int _config_def_check_node_value ( const char * rp , const struct dm_config_value * v ,
const cfg_def_item_t * def , int suppress_messages )
{
if ( ! v ) {
if ( def - > type ! = CFG_TYPE_SECTION ) {
_log_type_error ( rp , CFG_TYPE_SECTION , def - > type , suppress_messages ) ;
return 0 ;
}
return 1 ;
}
if ( v - > next ) {
if ( ! ( def - > type & CFG_TYPE_ARRAY ) ) {
_log_type_error ( rp , CFG_TYPE_ARRAY , def - > type , suppress_messages ) ;
return 0 ;
}
}
do {
if ( ! _config_def_check_node_single_value ( rp , v , def , suppress_messages ) )
return 0 ;
v = v - > next ;
} while ( v ) ;
return 1 ;
}
static int _config_def_check_node ( const char * vp , char * pvp , char * rp , char * prp ,
size_t buf_size , struct dm_config_node * cn ,
struct dm_hash_table * ht , int suppress_messages )
{
cfg_def_item_t * def ;
int sep = vp ! = pvp ; /* don't use '/' separator for top-level node */
if ( dm_snprintf ( pvp , buf_size , " %s%s " , sep ? " / " : " " , cn - > key ) < 0 | |
dm_snprintf ( prp , buf_size , " %s%s " , sep ? " / " : " " , cn - > key ) < 0 ) {
log_error ( " Failed to construct path for configuration node %s. " , cn - > key ) ;
return 0 ;
}
if ( ! ( def = ( cfg_def_item_t * ) dm_hash_lookup ( ht , vp ) ) ) {
/* If the node is not a section but a setting, fail now. */
if ( cn - > v ) {
log_warn_suppress ( suppress_messages ,
" Configuration setting \" %s \" unknown. " , rp ) ;
config: add support for enhanced config node output
There's a possibility to interconnect the dm_config_node with an
ID, which in our case is used to reference the configuration
definition ID from config_settings.h. So simply interconnecting
struct dm_config_node with struct cfg_def_item.
This patch also adds support for enhanced config node output besides
existing "output line by line". This patch adds a possibility to
register a callback that gets called *before* the config node is
processed line by line (for example to include any headers on output)
and *after* the config node is processed line by line (to include any
footers on output). Also, it adds the config node reference itself
as the callback arg in addition to have a possibility to extract more
information from the config node itself if needed when processing the
output callback (e.g. the key name, the id, or whether this is a
section or a value etc...).
If the config node from lvm.conf/--config tree is recognized and valid,
it's always coupled with the config node definition ID from
config_settings.h:
struct dm_config_node {
int id;
const char *key;
struct dm_config_node *parent, *sib, *child;
struct dm_config_value *v;
}
For example if the dm_config_node *cn holds "devices/dev" configuration,
then the cn->id holds "devices_dev_CFG" ID from config_settings.h, -1 if
not found in config_settings.h and 0 if matching has not yet been done.
To support the enhanced config node output, a new structure has been
defined in libdevmapper to register it:
struct dm_config_node_out_spec {
dm_config_node_out_fn prefix_fn; /* called before processing config node lines */
dm_config_node_out_fn line_fn; /* called for each config node line */
dm_config_node_out_fn suffix_fn; /* called after processing config node lines */
};
Where dm_config_node_out_fn is:
typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton);
(so in comparison to existing callbacks for config node output, it has
an extra dm_config_node *cn arg in addition)
This patch also adds these functions to libdevmapper:
- dm_config_write_node_out
- dm_config_write_one_node_out
...which have exactly the same functionality as their counterparts
without the "out" suffix. The "*_out" functions adds the extra hooks
for enhanced config output (prefix_fn and suffix_fn mentioned above).
One can still use the old interface for config node output, this is
just an enhancement for those who'd like to modify the output more
extensively.
2013-03-05 18:02:13 +01:00
cn - > id = - 1 ;
2013-03-05 17:14:18 +01:00
return 0 ;
}
/* If the node is a section, try if the section name is variable. */
/* Modify virtual path vp in situ and replace the key name with a '#'. */
/* The real path without '#' is still stored in rp variable. */
pvp [ sep ] = ' # ' , pvp [ sep + 1 ] = ' \0 ' ;
if ( ! ( def = ( cfg_def_item_t * ) dm_hash_lookup ( ht , vp ) ) ) {
log_warn_suppress ( suppress_messages ,
" Configuration section \" %s \" unknown. " , rp ) ;
config: add support for enhanced config node output
There's a possibility to interconnect the dm_config_node with an
ID, which in our case is used to reference the configuration
definition ID from config_settings.h. So simply interconnecting
struct dm_config_node with struct cfg_def_item.
This patch also adds support for enhanced config node output besides
existing "output line by line". This patch adds a possibility to
register a callback that gets called *before* the config node is
processed line by line (for example to include any headers on output)
and *after* the config node is processed line by line (to include any
footers on output). Also, it adds the config node reference itself
as the callback arg in addition to have a possibility to extract more
information from the config node itself if needed when processing the
output callback (e.g. the key name, the id, or whether this is a
section or a value etc...).
If the config node from lvm.conf/--config tree is recognized and valid,
it's always coupled with the config node definition ID from
config_settings.h:
struct dm_config_node {
int id;
const char *key;
struct dm_config_node *parent, *sib, *child;
struct dm_config_value *v;
}
For example if the dm_config_node *cn holds "devices/dev" configuration,
then the cn->id holds "devices_dev_CFG" ID from config_settings.h, -1 if
not found in config_settings.h and 0 if matching has not yet been done.
To support the enhanced config node output, a new structure has been
defined in libdevmapper to register it:
struct dm_config_node_out_spec {
dm_config_node_out_fn prefix_fn; /* called before processing config node lines */
dm_config_node_out_fn line_fn; /* called for each config node line */
dm_config_node_out_fn suffix_fn; /* called after processing config node lines */
};
Where dm_config_node_out_fn is:
typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton);
(so in comparison to existing callbacks for config node output, it has
an extra dm_config_node *cn arg in addition)
This patch also adds these functions to libdevmapper:
- dm_config_write_node_out
- dm_config_write_one_node_out
...which have exactly the same functionality as their counterparts
without the "out" suffix. The "*_out" functions adds the extra hooks
for enhanced config output (prefix_fn and suffix_fn mentioned above).
One can still use the old interface for config node output, this is
just an enhancement for those who'd like to modify the output more
extensively.
2013-03-05 18:02:13 +01:00
cn - > id = - 1 ;
2013-03-05 17:14:18 +01:00
return 0 ;
}
}
def - > flags | = CFG_USED ;
config: add support for enhanced config node output
There's a possibility to interconnect the dm_config_node with an
ID, which in our case is used to reference the configuration
definition ID from config_settings.h. So simply interconnecting
struct dm_config_node with struct cfg_def_item.
This patch also adds support for enhanced config node output besides
existing "output line by line". This patch adds a possibility to
register a callback that gets called *before* the config node is
processed line by line (for example to include any headers on output)
and *after* the config node is processed line by line (to include any
footers on output). Also, it adds the config node reference itself
as the callback arg in addition to have a possibility to extract more
information from the config node itself if needed when processing the
output callback (e.g. the key name, the id, or whether this is a
section or a value etc...).
If the config node from lvm.conf/--config tree is recognized and valid,
it's always coupled with the config node definition ID from
config_settings.h:
struct dm_config_node {
int id;
const char *key;
struct dm_config_node *parent, *sib, *child;
struct dm_config_value *v;
}
For example if the dm_config_node *cn holds "devices/dev" configuration,
then the cn->id holds "devices_dev_CFG" ID from config_settings.h, -1 if
not found in config_settings.h and 0 if matching has not yet been done.
To support the enhanced config node output, a new structure has been
defined in libdevmapper to register it:
struct dm_config_node_out_spec {
dm_config_node_out_fn prefix_fn; /* called before processing config node lines */
dm_config_node_out_fn line_fn; /* called for each config node line */
dm_config_node_out_fn suffix_fn; /* called after processing config node lines */
};
Where dm_config_node_out_fn is:
typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton);
(so in comparison to existing callbacks for config node output, it has
an extra dm_config_node *cn arg in addition)
This patch also adds these functions to libdevmapper:
- dm_config_write_node_out
- dm_config_write_one_node_out
...which have exactly the same functionality as their counterparts
without the "out" suffix. The "*_out" functions adds the extra hooks
for enhanced config output (prefix_fn and suffix_fn mentioned above).
One can still use the old interface for config node output, this is
just an enhancement for those who'd like to modify the output more
extensively.
2013-03-05 18:02:13 +01:00
cn - > id = def - > id ;
2013-03-05 17:14:18 +01:00
if ( ! _config_def_check_node_value ( rp , cn - > v , def , suppress_messages ) )
2013-03-05 17:48:29 +01:00
return 0 ;
2013-03-05 17:14:18 +01:00
def - > flags | = CFG_VALID ;
return 1 ;
}
static int _config_def_check_tree ( const char * vp , char * pvp , char * rp , char * prp ,
size_t buf_size , struct dm_config_node * root ,
struct dm_hash_table * ht , int suppress_messages )
{
struct dm_config_node * cn ;
int valid , r = 1 ;
size_t len ;
for ( cn = root - > child ; cn ; cn = cn - > sib ) {
if ( ( valid = _config_def_check_node ( vp , pvp , rp , prp , buf_size ,
cn , ht , suppress_messages ) ) & & ! cn - > v ) {
len = strlen ( rp ) ;
valid = _config_def_check_tree ( vp , pvp + strlen ( pvp ) ,
rp , prp + len , buf_size - len , cn , ht ,
suppress_messages ) ;
}
if ( ! valid )
r = 0 ;
}
return r ;
}
int config_def_check ( struct cmd_context * cmd , int force , int skip , int suppress_messages )
{
cfg_def_item_t * def ;
struct dm_config_node * cn ;
char * vp = _cfg_path , rp [ CFG_PATH_MAX_LEN ] ;
size_t rplen ;
int id , r = 1 ;
/*
* vp = virtual path , it might contain substitutes for variable parts
* of the path , used while working with the hash
* rp = real path , the real path of the config element as found in the
* configuration , used for message output
*/
/*
* If the check has already been done and ' skip ' is set ,
* skip the actual check and use last result if available .
* If not available , we must do the check . The global status
* is stored in root node .
*/
def = cfg_def_get_item_p ( root_CFG_SECTION ) ;
if ( skip & & ( def - > flags & CFG_USED ) )
return def - > flags & CFG_VALID ;
/* Clear 'used' and 'valid' status flags. */
for ( id = 0 ; id < CFG_COUNT ; id + + ) {
def = cfg_def_get_item_p ( id ) ;
def - > flags & = ~ ( CFG_USED | CFG_VALID ) ;
}
if ( ! force & & ! find_config_tree_bool ( cmd , config_checks_CFG ) ) {
if ( cmd - > cft_def_hash ) {
dm_hash_destroy ( cmd - > cft_def_hash ) ;
cmd - > cft_def_hash = NULL ;
}
return 1 ;
}
/*
* Create a hash of all possible configuration
* sections and settings with full path as a key .
* If section name is variable , use ' # ' as a substitute .
*/
if ( ! cmd - > cft_def_hash ) {
if ( ! ( cmd - > cft_def_hash = dm_hash_create ( 64 ) ) ) {
log_error ( " Failed to create configuration definition hash. " ) ;
r = 0 ; goto out ;
}
for ( id = 1 ; id < CFG_COUNT ; id + + ) {
def = cfg_def_get_item_p ( id ) ;
if ( ! cfg_def_get_path ( def ) ) {
dm_hash_destroy ( cmd - > cft_def_hash ) ;
cmd - > cft_def_hash = NULL ;
r = 0 ; goto out ;
}
2013-04-21 13:12:58 +02:00
if ( ! dm_hash_insert ( cmd - > cft_def_hash , vp , def ) ) {
log_error ( " Failed to insert configuration to hash. " ) ;
r = 0 ;
goto out ;
}
2013-03-05 17:14:18 +01:00
}
}
cfg_def_get_item_p ( root_CFG_SECTION ) - > flags | = CFG_USED ;