2001-08-21 16:56:08 +04:00
/*
2007-07-09 02:51:20 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2011-05-24 17:53:26 +04:00
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
2001-08-21 16:56:08 +04:00
*
2004-03-30 23:35:44 +04: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-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04: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 16:56:08 +04:00
*/
2011-08-30 18:55:15 +04:00
2002-11-18 17:01:16 +03:00
# include "lib.h"
2011-08-30 18:55:15 +04:00
2002-11-18 17:01:16 +03:00
# include "config.h"
# include "crc.h"
# include "device.h"
2004-05-04 22:28:15 +04:00
# include "str_list.h"
# include "toolcontext.h"
2007-04-26 00:38:39 +04:00
# include "lvm-string.h"
2007-07-24 21:48:08 +04:00
# include "lvm-file.h"
2002-11-18 17:01:16 +03:00
2001-08-21 16:56:08 +04:00
# include <sys/stat.h>
# include <sys/mman.h>
# include <unistd.h>
# include <fcntl.h>
# include <ctype.h>
2001-09-13 16:38:31 +04:00
2011-08-30 18:55:15 +04:00
void destroy_config_tree ( struct dm_config_tree * cft )
2002-01-07 13:23:52 +03:00
{
2011-08-30 18:55:15 +04:00
struct device * dev = dm_config_get_custom ( cft ) ;
2002-01-07 13:23:52 +03:00
2011-08-30 18:55:15 +04:00
if ( dev )
dev_close ( dev ) ;
2002-01-07 13:23:52 +03:00
2011-08-30 18:55:15 +04:00
dm_config_destroy ( cft ) ;
2006-05-16 20:48:31 +04:00
}
2011-09-02 05:32:08 +04:00
/*
* Returns config tree if it was removed .
*/
struct dm_config_tree * remove_overridden_config_tree ( struct cmd_context * cmd )
{
2011-09-02 05:59:07 +04:00
// FIXME Replace cmd->cft with clean copy of merged lvm*.conf tree
2011-09-02 05:32:08 +04:00
struct dm_config_tree * old_cft = cmd - > cft ;
struct dm_config_tree * cft = dm_config_remove_cascaded_tree ( cmd - > cft ) ;
if ( ! cft )
return NULL ;
cmd - > cft = cft ;
return old_cft ;
}
2011-09-02 05:59:07 +04:00
// FIXME Retain a copy of the string (or tree?) in cmd->cft_cmdline
// FIXME and merge into cmd->cft
2009-07-28 01:01:56 +04:00
int override_config_tree_from_string ( struct cmd_context * cmd ,
const char * config_settings )
{
2011-09-02 05:32:08 +04:00
struct dm_config_tree * cft_new ;
if ( ! ( cft_new = dm_config_from_string ( config_settings ) ) ) {
2009-07-28 01:01:56 +04:00
log_error ( " Failed to set overridden configuration entries. " ) ;
return 1 ;
}
2011-09-02 05:32:08 +04:00
cmd - > cft = dm_config_insert_cascaded_tree ( cft_new , cmd - > cft ) ;
2009-07-28 01:01:56 +04:00
return 0 ;
}
2011-08-30 18:55:15 +04:00
int read_config_fd ( struct dm_config_tree * cft , struct device * dev ,
2002-12-20 02:25:55 +03:00
off_t offset , size_t size , off_t offset2 , size_t size2 ,
2002-11-18 17:01:16 +03:00
checksum_fn_t checksum_fn , uint32_t checksum )
2001-08-21 16:56:08 +04:00
{
2011-08-30 18:55:15 +04:00
const char * fb , * fe ;
2002-11-18 17:01:16 +03:00
int r = 0 ;
2003-07-05 02:34:56 +04:00
int use_mmap = 1 ;
off_t mmap_offset = 0 ;
2007-06-13 19:11:19 +04:00
char * buf = NULL ;
2002-04-24 22:20:51 +04:00
2003-07-05 02:34:56 +04:00
/* Only use mmap with regular files */
if ( ! ( dev - > flags & DEV_REGULAR ) | | size2 )
use_mmap = 0 ;
if ( use_mmap ) {
2006-08-17 22:23:44 +04:00
mmap_offset = offset % lvm_getpagesize ( ) ;
2002-11-18 17:01:16 +03:00
/* memory map the file */
2011-08-30 18:55:15 +04: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-05 02:34:56 +04:00
log_sys_error ( " mmap " , dev_name ( dev ) ) ;
2002-11-18 17:01:16 +03:00
goto out ;
}
2011-08-30 18:55:15 +04:00
fb = fb + mmap_offset ;
2003-07-05 02:34:56 +04:00
} else {
2008-01-30 16:19:47 +03:00
if ( ! ( buf = dm_malloc ( size + size2 ) ) )
return_0 ;
2007-04-19 06:10:42 +04:00
if ( ! dev_read_circular ( dev , ( uint64_t ) offset , size ,
( uint64_t ) offset2 , size2 , buf ) ) {
2003-07-05 02:34:56 +04:00
goto out ;
}
2011-08-30 18:55:15 +04:00
fb = buf ;
2002-11-18 17:01:16 +03:00
}
if ( checksum_fn & & checksum ! =
2011-08-30 18:55:15 +04:00
( checksum_fn ( checksum_fn ( INITIAL_CRC , ( const uint8_t * ) fb , size ) ,
( const uint8_t * ) ( fb + size ) , size2 ) ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " %s: Checksum error " , dev_name ( dev ) ) ;
2002-11-18 17:01:16 +03:00
goto out ;
}
2011-08-30 18:55:15 +04:00
fe = fb + size + size2 ;
if ( ! dm_config_parse ( cft , fb , fe ) )
2008-01-30 16:19:47 +03:00
goto_out ;
2002-11-18 17:01:16 +03:00
r = 1 ;
out :
2003-07-05 02:34:56 +04:00
if ( ! use_mmap )
2006-05-16 20:48:31 +04:00
dm_free ( buf ) ;
2002-11-18 17:01:16 +03:00
else {
/* unmap the file */
2011-08-30 18:55:15 +04:00
if ( munmap ( ( char * ) ( fb - mmap_offset ) , size + mmap_offset ) ) {
2003-07-05 02:34:56 +04:00
log_sys_error ( " munmap " , dev_name ( dev ) ) ;
2002-11-18 17:01:16 +03:00
r = 0 ;
}
}
return r ;
}
2011-08-30 18:55:15 +04:00
int read_config_file ( struct dm_config_tree * cft )
2002-11-18 17:01:16 +03:00
{
2011-09-02 05:32:08 +04:00
const char * filename = NULL ;
2011-08-30 18:55:15 +04:00
struct device * dev = dm_config_get_custom ( cft ) ;
2002-11-18 17:01:16 +03:00
struct stat info ;
2011-08-30 18:55:15 +04:00
int r ;
2002-04-24 22:20:51 +04:00
2011-08-30 18:55:15 +04:00
if ( ! dm_config_check_file ( cft , & filename , & info ) )
2011-09-02 01:04:14 +04:00
return_0 ;
2004-05-04 22:28:15 +04:00
2011-09-02 05:32:08 +04:00
/* Nothing to do. E.g. empty file. */
if ( ! filename )
return 1 ;
2011-08-30 18:55:15 +04:00
if ( ! dev ) {
if ( ! ( dev = dev_create_file ( filename , NULL , NULL , 1 ) ) )
2006-11-04 06:34:10 +03:00
return_0 ;
2003-07-05 02:34:56 +04:00
2011-08-30 18:55:15 +04:00
if ( ! dev_open_readonly_buffered ( dev ) )
2006-11-04 06:34:10 +03:00
return_0 ;
2002-04-24 22:20:51 +04:00
}
2011-08-30 18:55:15 +04:00
dm_config_set_custom ( cft , dev ) ;
r = read_config_fd ( cft , dev , 0 , ( size_t ) info . st_size , 0 , 0 ,
2002-11-18 17:01:16 +03:00
( checksum_fn_t ) NULL , 0 ) ;
2011-08-30 18:55:15 +04:00
if ( ! dm_config_keep_open ( cft ) ) {
dev_close ( dev ) ;
dm_config_set_custom ( cft , NULL ) ;
2006-11-04 06:34:10 +03:00
}
2002-11-18 17:01:16 +03:00
return r ;
}
2011-08-30 18:55:15 +04:00
const struct dm_config_node * find_config_tree_node ( struct cmd_context * cmd ,
2010-12-20 16:12:55 +03:00
const char * path )
2001-08-21 16:56:08 +04:00
{
2011-09-02 05:32:08 +04:00
return dm_config_tree_find_node ( cmd - > cft , path ) ;
2006-05-16 20:48:31 +04:00
}
const char * find_config_tree_str ( struct cmd_context * cmd ,
2007-07-09 02:51:20 +04:00
const char * path , const char * fail )
2006-05-16 20:48:31 +04:00
{
2011-09-02 05:32:08 +04:00
return dm_config_tree_find_str ( cmd - > cft , path , fail ) ;
2006-05-16 20:48:31 +04:00
}
int find_config_tree_int ( struct cmd_context * cmd , const char * path ,
2007-07-09 02:51:20 +04:00
int fail )
2006-05-16 20:48:31 +04:00
{
2011-09-02 05:32:08 +04:00
return dm_config_tree_find_int ( cmd - > cft , path , fail ) ;
2006-05-16 20:48:31 +04:00
}
2011-02-18 17:08:22 +03:00
int64_t find_config_tree_int64 ( struct cmd_context * cmd , const char * path , int64_t fail )
{
2011-09-02 05:32:08 +04:00
return dm_config_tree_find_int64 ( cmd - > cft , path , fail ) ;
2011-02-18 17:08:22 +03:00
}
2006-05-16 20:48:31 +04:00
float find_config_tree_float ( struct cmd_context * cmd , const char * path ,
2007-07-09 02:51:20 +04:00
float fail )
2006-05-16 20:48:31 +04:00
{
2011-09-02 05:32:08 +04:00
return dm_config_tree_find_float ( cmd - > cft , path , fail ) ;
2006-05-16 20:48:31 +04:00
}
int find_config_tree_bool ( struct cmd_context * cmd , const char * path , int fail )
{
2011-09-02 05:32:08 +04:00
return dm_config_tree_find_bool ( cmd - > cft , path , fail ) ;
2002-07-11 18:07:43 +04:00
}
2004-05-04 22:28:15 +04:00
/* Insert cn2 after cn1 */
2011-08-30 18:55:15 +04:00
static void _insert_config_node ( struct dm_config_node * * cn1 ,
struct dm_config_node * cn2 )
2004-05-04 22:28:15 +04:00
{
if ( ! * cn1 ) {
* cn1 = cn2 ;
cn2 - > sib = NULL ;
} else {
cn2 - > sib = ( * cn1 ) - > sib ;
( * cn1 ) - > sib = cn2 ;
}
}
/*
* Merge section cn2 into section cn1 ( which has the same name )
* overwriting any existing cn1 nodes with matching names .
*/
2011-08-30 18:55:15 +04:00
static void _merge_section ( struct dm_config_node * cn1 , struct dm_config_node * cn2 )
2004-05-04 22:28:15 +04:00
{
2011-08-30 18:55:15 +04:00
struct dm_config_node * cn , * nextn , * oldn ;
struct dm_config_value * cv ;
2004-05-04 22:28:15 +04:00
for ( cn = cn2 - > child ; cn ; cn = nextn ) {
nextn = cn - > sib ;
/* Skip "tags" */
if ( ! strcmp ( cn - > key , " tags " ) )
continue ;
/* Subsection? */
if ( ! cn - > v )
/* Ignore - we don't have any of these yet */
continue ;
/* Not already present? */
2011-08-31 19:19:19 +04:00
if ( ! ( oldn = dm_config_find_node ( cn1 - > child , cn - > key ) ) ) {
2004-05-04 22:28:15 +04:00
_insert_config_node ( & cn1 - > child , cn ) ;
continue ;
}
/* Merge certain value lists */
if ( ( ! strcmp ( cn1 - > key , " activation " ) & &
! strcmp ( cn - > key , " volume_list " ) ) | |
( ! strcmp ( cn1 - > key , " devices " ) & &
( ! strcmp ( cn - > key , " filter " ) | | ! strcmp ( cn - > key , " types " ) ) ) ) {
cv = cn - > v ;
while ( cv - > next )
cv = cv - > next ;
cv - > next = oldn - > v ;
}
/* Replace values */
oldn - > v = cn - > v ;
}
}
2011-08-30 18:55:15 +04:00
static int _match_host_tags ( struct dm_list * tags , const struct dm_config_node * tn )
2004-05-04 22:28:15 +04:00
{
2011-08-30 18:55:15 +04:00
const struct dm_config_value * tv ;
2004-05-04 22:28:15 +04:00
const char * str ;
for ( tv = tn - > v ; tv ; tv = tv - > next ) {
2011-08-30 18:55:15 +04:00
if ( tv - > type ! = DM_CFG_STRING )
2004-05-04 22:28:15 +04:00
continue ;
str = tv - > v . str ;
if ( * str = = ' @ ' )
str + + ;
if ( ! * str )
continue ;
if ( str_list_match_item ( tags , str ) )
return 1 ;
}
return 0 ;
}
/* Destructively merge a new config tree into an existing one */
2011-08-30 18:55:15 +04:00
int merge_config_tree ( struct cmd_context * cmd , struct dm_config_tree * cft ,
struct dm_config_tree * newdata )
2004-05-04 22:28:15 +04:00
{
2011-08-31 19:19:19 +04:00
struct dm_config_node * root = cft - > root ;
2011-08-30 18:55:15 +04:00
struct dm_config_node * cn , * nextn , * oldn , * cn2 ;
const struct dm_config_node * tn ;
2004-05-04 22:28:15 +04:00
for ( cn = newdata - > root ; cn ; cn = nextn ) {
nextn = cn - > sib ;
/* Ignore tags section */
if ( ! strcmp ( cn - > key , " tags " ) )
continue ;
/* If there's a tags node, skip if host tags don't match */
2011-08-30 18:55:15 +04:00
if ( ( tn = dm_config_find_node ( cn - > child , " tags " ) ) ) {
2004-05-04 22:28:15 +04:00
if ( ! _match_host_tags ( & cmd - > tags , tn ) )
continue ;
}
2011-08-31 19:19:19 +04:00
if ( ! ( oldn = dm_config_find_node ( root , cn - > key ) ) ) {
2004-05-04 22:28:15 +04:00
_insert_config_node ( & cft - > root , cn ) ;
/* Remove any "tags" nodes */
for ( cn2 = cn - > child ; cn2 ; cn2 = cn2 - > sib ) {
if ( ! strcmp ( cn2 - > key , " tags " ) ) {
cn - > child = cn2 - > sib ;
continue ;
}
if ( cn2 - > sib & & ! strcmp ( cn2 - > sib - > key , " tags " ) ) {
cn2 - > sib = cn2 - > sib - > sib ;
continue ;
}
}
continue ;
}
_merge_section ( oldn , cn ) ;
}
return 1 ;
}
2007-04-26 00:38:39 +04:00