[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH] Move config parsing/prettyprinting infrastructure to libdevmapper



Hi,

this is the first patch towards integrating the new daemon
infrastructure (and, ultimately, lvmetad) into the build. This patch
moves the core of the lib/config/config.c functionality into
libdevmapper, leaving behind the LVM-specific parts of the code
(convenience wrappers that handle `struct device` and `struct
cmd_context`, basically).

In the process, I have pragmatically moved part of the lvm-string.c code
into libdm-string.c, to avoid duplicating shared helpers. This shouldn't
be a big deal. As another measure to make the move smoother, I have
slightly generalised the code to handle config overrides (by allowing a
cascade of config_trees to exist, and adapting the existing
find_config_tree* functionality in lib/config/config.c to leverage this
more generic code).

As an aside, the existing code for handling multiple configurations
could be moved over to use this same mechanism, with the added benefit
of making the implied cascading actually work (currently, cascading only
works on the level of config sections, i.e. only the list of sections is
actually cascaded, not the values inside, making it impossible to
override a specific key through cascading).

As for checking this in, the consensus seems to be towards cvs add-ing
the new files and checking this more or less in the form of the below
diff. The other option is to make a server-side copy of
lib/config/config.c to libdm/libdm-config.c (I will then check this in
on top of that, making the diff more useful).

Also, please try to review this quickly, as it is pretty much a
powerplant patch, and I would hate to get caught up in a conflict mess
here (unfortunately, not everything in the patch can be mechanically
repeated).

For reference, I have used the following sed script to move over most of
the code to the new names:

s,\<struct config_tree\>,struct dm_config_tree,g
s,\<struct config_node\>,struct dm_config_node,g
s,\<struct config_value\>,struct dm_config_value,g

s,\<find_config_str\>,dm_config_find_str,g
s,\<find_config_int\>,dm_config_find_int,g
s,\<find_config_node\>,dm_config_find_node,g

s,\<get_config_str\>,dm_config_get_str,g
s,\<get_config_uint64\>,dm_config_get_uint64,g
s,\<get_config_uint32\>,dm_config_get_uint32,g

s,\<config_parent_name\>,dm_config_parent_name,g

s,\<CFG_STRING\>,DM_CFG_STRING,g
s,\<CFG_INT\>,DM_CFG_INT,g
s,\<CFG_EMPTY_ARRAY\>,DM_CFG_EMPTY_ARRAY,g

s,\<write_config_node\>,dm_config_write_node,g
s,\<write_config_file\>,dm_config_write,g

s,\<clone_config_node_with_mem\>,dm_config_clone_node_with_mem,g
s,\<clone_config_node\>,dm_config_clone_node,g

s,\<maybe_config_section\>,dm_config_maybe_section,g

s,\<struct config_tree_list\>,struct dm_config_tree_list,g
s,= create_config_tree\>,= dm_config_create,g
s,\<config_file_changed\>,dm_config_changed,g
s,\<config_file_timestamp\>,dm_config_timestamp,g

s,\<build_dm_name\>,dm_build_dm_name,g
s,\<escape_double_quotes\>,dm_escape_double_quotes,g
s,\<escaped_len\>,dm_escaped_len,g
s,\<unescape_colons_and_at_signs\>,dm_unescape_colons_and_at_signs,g

Yours,
   Petr

diff -ruN -xCVS cvs-clean/lib/activate/activate.c cvs-daemons-reorg/lib/activate/activate.c
--- cvs-clean/lib/activate/activate.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/activate/activate.c	2011-08-29 19:41:48.000000000 +0200
@@ -273,8 +273,8 @@
 static int _passes_activation_filter(struct cmd_context *cmd,
 				     struct logical_volume *lv)
 {
-	const struct config_node *cn;
-	const struct config_value *cv;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *cv;
 	const char *str;
 	char path[PATH_MAX];
 
@@ -304,7 +304,7 @@
 			    lv->vg->name, lv->name);
 
 	for (cv = cn->v; cv; cv = cv->next) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Ignoring invalid string in config file "
 				  "activation/volume_list");
 			continue;
diff -ruN -xCVS cvs-clean/lib/activate/dev_manager.c cvs-daemons-reorg/lib/activate/dev_manager.c
--- cvs-clean/lib/activate/dev_manager.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/activate/dev_manager.c	2011-08-29 19:41:48.000000000 +0200
@@ -269,7 +269,7 @@
 	char *dlid, *name;
 	int r;
 
-	if (!(name = build_dm_name(mem, lv->vg->name, lv->name, layer))) {
+	if (!(name = dm_build_dm_name(mem, lv->vg->name, lv->name, layer))) {
 		log_error("name build failed for %s", lv->name);
 		return 0;
 	}
@@ -723,7 +723,7 @@
 	/*
 	 * Build a name for the top layer.
 	 */
-	if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL)))
+	if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, NULL)))
 		return_0;
 
 	if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, NULL)))
@@ -757,7 +757,7 @@
 	/*
 	 * Build a name for the top layer.
 	 */
-	if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+	if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
 		return_0;
 
 	/* FIXME dm_pool_free ? */
@@ -800,7 +800,7 @@
 	/* Rename? */
 		if ((suffix = strrchr(dl->dlid + sizeof(UUID_PREFIX) - 1, '-')))
 			suffix++;
-		new_name = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
+		new_name = dm_build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
 					suffix);
 
 static int _belong_to_vg(const char *vgname, const char *name)
@@ -843,7 +843,7 @@
 {
 	char *name;
 
-	if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
+	if (!(name = dm_build_dm_name(lv->vg->cmd->mem, lv->vg->name,
 				   lv->name, NULL)))
 		return_0;
 
@@ -861,7 +861,7 @@
 	char *name;
 	int r = 0;
 
-	if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name, lv->name, NULL)))
+	if (!(name = dm_build_dm_name(lv->vg->cmd->mem, lv->vg->name, lv->name, NULL)))
 		return_0;
 
 	if ((r = _info_run(name, NULL, &dminfo, NULL, 1, 0, 0, 0, 0))) {
@@ -933,7 +933,7 @@
 	char *dlid, *name;
 	struct dm_info info, info2;
 
-	if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+	if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
 		return_0;
 
 	if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer)))
@@ -1163,7 +1163,7 @@
 	if (!(id = build_dm_uuid(dm->mem, seg->lv->lvid.s, errid)))
 		return_NULL;
 
-	if (!(name = build_dm_name(dm->mem, seg->lv->vg->name,
+	if (!(name = dm_build_dm_name(dm->mem, seg->lv->vg->name,
 				   seg->lv->name, errid)))
 		return_NULL;
 	if (!(node = dm_tree_add_new_dev(dtree, name, id, 0, 0, 0, 0, 0)))
@@ -1558,7 +1558,7 @@
 		}
 	}
 
-	if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+	if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
 		return_0;
 
 	if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer)))
diff -ruN -xCVS cvs-clean/lib/cache/lvmcache.c cvs-daemons-reorg/lib/cache/lvmcache.c
--- cvs-clean/lib/cache/lvmcache.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/cache/lvmcache.c	2011-08-29 19:41:48.000000000 +0200
@@ -677,7 +677,7 @@
 	/* Build config tree from vgmetadata, if not yet cached */
 	if (!vginfo->cft &&
 	    !(vginfo->cft =
-	      create_config_tree_from_string(vginfo->vgmetadata)))
+	      dm_config_from_string(vginfo->vgmetadata)))
 		goto_bad;
 
 	if (!(vg = import_vg_from_config_tree(vginfo->cft, fid)))
diff -ruN -xCVS cvs-clean/lib/cache/lvmcache.h cvs-daemons-reorg/lib/cache/lvmcache.h
--- cvs-clean/lib/cache/lvmcache.h	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/cache/lvmcache.h	2011-08-29 19:41:48.000000000 +0200
@@ -33,7 +33,7 @@
 struct cmd_context;
 struct format_type;
 struct volume_group;
-struct config_tree;
+struct dm_config_tree;
 
 /* One per VG */
 struct lvmcache_vginfo {
@@ -48,8 +48,8 @@
 	char *creation_host;
 	size_t vgmetadata_size;
 	char *vgmetadata;	/* Copy of VG metadata as format_text string */
-	struct config_tree *cft; /* Config tree created from vgmetadata */
-				/* Lifetime is directly tied to vgmetadata */
+	struct dm_config_tree *cft; /* Config tree created from vgmetadata */
+				    /* Lifetime is directly tied to vgmetadata */
 	struct volume_group *cached_vg;
 	unsigned holders;
 	unsigned vg_use_count;	/* Counter of vg reusage */
diff -ruN -xCVS cvs-clean/lib/commands/toolcontext.c cvs-daemons-reorg/lib/commands/toolcontext.c
--- cvs-clean/lib/commands/toolcontext.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/commands/toolcontext.c	2011-08-29 19:41:48.000000000 +0200
@@ -222,8 +222,8 @@
 	mode_t old_umask;
 	const char *read_ahead;
 	struct stat st;
-	const struct config_node *cn;
-	const struct config_value *cv;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *cv;
 	int64_t pv_min_kb;
 
 	/* umask */
@@ -358,7 +358,7 @@
 
 	if ((cn = find_config_tree_node(cmd, "activation/mlock_filter")))
 		for (cv = cn->v; cv; cv = cv->next) 
-			if ((cv->type != CFG_STRING) || !cv->v.str[0]) 
+			if ((cv->type != DM_CFG_STRING) || !cv->v.str[0]) 
 				log_error("Ignoring invalid activation/mlock_filter entry in config file");
 
 	cmd->metadata_read_only = find_config_tree_int(cmd, "global/metadata_read_only",
@@ -392,11 +392,11 @@
 	return 1;
 }
 
-static int _check_host_filters(struct cmd_context *cmd, const struct config_node *hn,
+static int _check_host_filters(struct cmd_context *cmd, const struct dm_config_node *hn,
 			       int *passes)
 {
-	const struct config_node *cn;
-	const struct config_value *cv;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *cv;
 
 	*passes = 1;
 
@@ -405,10 +405,10 @@
 			continue;
 		if (!strcmp(cn->key, "host_list")) {
 			*passes = 0;
-			if (cn->v->type == CFG_EMPTY_ARRAY)
+			if (cn->v->type == DM_CFG_EMPTY_ARRAY)
 				continue;
 			for (cv = cn->v; cv; cv = cv->next) {
-				if (cv->type != CFG_STRING) {
+				if (cv->type != DM_CFG_STRING) {
 					log_error("Invalid hostname string "
 						  "for tag %s", cn->key);
 					return 0;
@@ -428,17 +428,17 @@
 	return 1;
 }
 
-static int _init_tags(struct cmd_context *cmd, struct config_tree *cft)
+static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
 {
-	const struct config_node *tn, *cn;
+	const struct dm_config_node *tn, *cn;
 	const char *tag;
 	int passes;
 
-	if (!(tn = find_config_node(cft->root, "tags")) || !tn->child)
+	if (!(tn = dm_config_find_node(cft->root, "tags")) || !tn->child)
 		return 1;
 
 	/* NB hosttags 0 when already 1 intentionally does not delete the tag */
-	if (!cmd->hosttags && find_config_int(cft->root, "tags/hosttags",
+	if (!cmd->hosttags && dm_config_find_int(cft->root, "tags/hosttags",
 					      DEFAULT_HOSTTAGS)) {
 		/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
 		if (!_set_tag(cmd, cmd->hostname))
@@ -491,7 +491,7 @@
 		return 0;
 	}
 
-	if (!(cfl->cft = create_config_tree(config_file, 0))) {
+	if (!(cfl->cft = dm_config_create(config_file, 0))) {
 		log_error("config_tree allocation failed");
 		return 0;
 	}
@@ -531,7 +531,7 @@
 {
 	/* No config file if LVM_SYSTEM_DIR is empty */
 	if (!*cmd->system_dir) {
-		if (!(cmd->cft = create_config_tree(NULL, 0))) {
+		if (!(cmd->cft = dm_config_create(NULL, 0))) {
 			log_error("Failed to create config tree");
 			return 0;
 		}
@@ -564,7 +564,7 @@
 
 	/* Replace temporary duplicate copy of lvm.conf */
 	if (cmd->cft->root) {
-		if (!(cmd->cft = create_config_tree(NULL, 0))) {
+		if (!(cmd->cft = dm_config_create(NULL, 0))) {
 			log_error("Failed to create config tree");
 			return 0;
 		}
@@ -593,7 +593,7 @@
 	struct config_tree_list *cfl;
 
 	dm_list_iterate_items(cfl, &cmd->config_files) {
-		if (config_file_changed(cfl->cft))
+		if (dm_config_changed(cfl->cft))
 			return 1;
 	}
 
@@ -620,8 +620,8 @@
 
 static int _init_dev_cache(struct cmd_context *cmd)
 {
-	const struct config_node *cn;
-	const struct config_value *cv;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *cv;
 	size_t uninitialized_var(udev_dir_len), len;
 	int device_list_from_udev;
 	const char *uninitialized_var(udev_dir);
@@ -653,7 +653,7 @@
 	}
 
 	for (cv = cn->v; cv; cv = cv->next) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Invalid string in config file: "
 				  "devices/scan");
 			return 0;
@@ -680,7 +680,7 @@
 		return 1;
 
 	for (cv = cn->v; cv; cv = cv->next) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Invalid string in config file: "
 				  "devices/loopfiles");
 			return 0;
@@ -702,7 +702,7 @@
 static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
 {
 	unsigned nr_filt = 0;
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	struct dev_filter *filters[MAX_FILTERS];
 
 	memset(filters, 0, sizeof(filters));
@@ -823,7 +823,7 @@
 	 */
 	if (load_persistent_cache && !cmd->is_long_lived &&
 	    !stat(dev_cache, &st) &&
-	    (st.st_ctime > config_file_timestamp(cmd->cft)) &&
+	    (st.st_ctime > dm_config_timestamp(cmd->cft)) &&
 	    !persistent_filter_load(f4, NULL))
 		log_verbose("Failed to load existing device cache from %s",
 			    dev_cache);
@@ -853,7 +853,7 @@
 	struct format_type *fmt;
 
 #ifdef HAVE_LIBDL
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 #endif
 
 	label_init();
@@ -877,12 +877,12 @@
 	if (!is_static() &&
 	    (cn = find_config_tree_node(cmd, "global/format_libraries"))) {
 
-		const struct config_value *cv;
+		const struct dm_config_value *cv;
 		struct format_type *(*init_format_fn) (struct cmd_context *);
 		void *lib;
 
 		for (cv = cn->v; cv; cv = cv->next) {
-			if (cv->type != CFG_STRING) {
+			if (cv->type != DM_CFG_STRING) {
 				log_error("Invalid string in config file: "
 					  "global/format_libraries");
 				return 0;
@@ -1010,7 +1010,7 @@
 	};
 
 #ifdef HAVE_LIBDL
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 #endif
 
 	for (i = 0; init_segtype_array[i]; i++) {
@@ -1040,12 +1040,12 @@
 	if (!is_static() &&
 	    (cn = find_config_tree_node(cmd, "global/segment_libraries"))) {
 
-		const struct config_value *cv;
+		const struct dm_config_value *cv;
 		int (*init_multiple_segtypes_fn) (struct cmd_context *,
 						  struct segtype_library *);
 
 		for (cv = cn->v; cv; cv = cv->next) {
-			if (cv->type != CFG_STRING) {
+			if (cv->type != DM_CFG_STRING) {
 				log_error("Invalid string in config file: "
 					  "global/segment_libraries");
 				return 0;
diff -ruN -xCVS cvs-clean/lib/commands/toolcontext.h cvs-daemons-reorg/lib/commands/toolcontext.h
--- cvs-clean/lib/commands/toolcontext.h	2011-07-11 12:45:19.000000000 +0200
+++ cvs-daemons-reorg/lib/commands/toolcontext.h	2011-08-29 19:42:19.000000000 +0200
@@ -47,11 +47,16 @@
 	char _padding[1];
 };
 
-struct config_tree;
+struct dm_config_tree;
 struct archive_params;
 struct backup_params;
 struct arg_values;
 
+struct config_tree_list {
+	struct dm_list list;
+	struct dm_config_tree *cft;
+};
+
 /* FIXME Split into tool & library contexts */
 /* command-instance-related variables needed by library */
 struct cmd_context {
@@ -87,8 +92,8 @@
 
 	struct dm_list config_files;
 	int config_valid;
-	struct config_tree *cft;
-	struct config_tree *cft_override;
+	struct dm_config_tree *cft;
+	struct dm_config_tree *cft_override;
 	struct config_info default_settings;
 	struct config_info current_settings;
 
diff -ruN -xCVS cvs-clean/lib/config/config.c cvs-daemons-reorg/lib/config/config.c
--- cvs-clean/lib/config/config.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/config/config.c	2011-08-29 19:46:26.000000000 +0200
@@ -13,7 +13,9 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+
 #include "lib.h"
+
 #include "config.h"
 #include "crc.h"
 #include "device.h"
@@ -28,170 +30,20 @@
 #include <fcntl.h>
 #include <ctype.h>
 
-#define SECTION_B_CHAR '{'
-#define SECTION_E_CHAR '}'
-
-enum {
-	TOK_INT,
-	TOK_FLOAT,
-	TOK_STRING,		/* Single quotes */
-	TOK_STRING_ESCAPED,	/* Double quotes */
-	TOK_EQ,
-	TOK_SECTION_B,
-	TOK_SECTION_E,
-	TOK_ARRAY_B,
-	TOK_ARRAY_E,
-	TOK_IDENTIFIER,
-	TOK_COMMA,
-	TOK_EOF
-};
-
-struct parser {
-	const char *fb, *fe;		/* file limits */
-
-	int t;			/* token limits and type */
-	const char *tb, *te;
-
-	int fd;			/* descriptor for file being parsed */
-	int line;		/* line number we are on */
-
-	struct dm_pool *mem;
-};
-
-struct cs {
-	struct config_tree cft;
-	struct dm_pool *mem;
-	time_t timestamp;
-	off_t st_size;
-	char *filename;
-	int exists;
-	int keep_open;
-	struct device *dev;
-};
-
-struct output_line {
-	FILE *fp;
-	struct dm_pool *mem;
-	putline_fn putline;
-	void *putline_baton;
-};
-
-static void _get_token(struct parser *p, int tok_prev);
-static void _eat_space(struct parser *p);
-static struct config_node *_file(struct parser *p);
-static struct config_node *_section(struct parser *p);
-static struct config_value *_value(struct parser *p);
-static struct config_value *_type(struct parser *p);
-static int _match_aux(struct parser *p, int t);
-static struct config_value *_create_value(struct dm_pool *mem);
-static struct config_node *_create_node(struct dm_pool *mem);
-static char *_dup_tok(struct parser *p);
-
-static const int sep = '/';
-
-#define MAX_INDENT 32
-
-#define match(t) do {\
-   if (!_match_aux(p, (t))) {\
-	log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
-		  p->tb - p->fb + 1, p->line); \
-      return 0;\
-   } \
-} while(0);
-
-static int _tok_match(const char *str, const char *b, const char *e)
-{
-	while (*str && (b != e)) {
-		if (*str++ != *b++)
-			return 0;
-	}
-
-	return !(*str || (b != e));
-}
-
-/*
- * public interface
- */
-struct config_tree *create_config_tree(const char *filename, int keep_open)
-{
-	struct cs *c;
-	struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
-
-	if (!mem) {
-		log_error("Failed to allocate config pool.");
-		return 0;
-	}
-
-	if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
-		log_error("Failed to allocate config tree.");
-		dm_pool_destroy(mem);
-		return 0;
-	}
-
-	c->mem = mem;
-	c->cft.root = (struct config_node *) NULL;
-	c->timestamp = 0;
-	c->exists = 0;
-	c->keep_open = keep_open;
-	c->dev = 0;
-	if (filename)
-		c->filename = dm_pool_strdup(c->mem, filename);
-	return &c->cft;
-}
-
-void destroy_config_tree(struct config_tree *cft)
-{
-	struct cs *c = (struct cs *) cft;
-
-	if (c->dev)
-		dev_close(c->dev);
-
-	dm_pool_destroy(c->mem);
-}
-
-static int _parse_config_file(struct parser *p, struct config_tree *cft)
-{
-	p->tb = p->te = p->fb;
-	p->line = 1;
-	_get_token(p, TOK_SECTION_E);
-	if (!(cft->root = _file(p)))
-		return_0;
-
-	return 1;
-}
-
-struct config_tree *create_config_tree_from_string(const char *config_settings)
+void destroy_config_tree(struct dm_config_tree *cft)
 {
-	struct cs *c;
-	struct config_tree *cft;
-	struct parser *p;
-
-	if (!(cft = create_config_tree(NULL, 0)))
-		return_NULL;
-
-	c = (struct cs *) cft;
-	if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
-		log_error("Failed to allocate config tree parser.");
-		destroy_config_tree(cft);
-		return NULL;
-	}
+	struct device *dev = dm_config_get_custom(cft);
 
-	p->mem = c->mem;
-	p->fb = config_settings;
-	p->fe = config_settings + strlen(config_settings);
-
-	if (!_parse_config_file(p, cft)) {
-		destroy_config_tree(cft);
-		return_NULL;
-	}
+	if (dev)
+		dev_close(dev);
 
-	return cft;
+	dm_config_destroy(cft);
 }
 
 int override_config_tree_from_string(struct cmd_context *cmd,
 				     const char *config_settings)
 {
-	if (!(cmd->cft_override = create_config_tree_from_string(config_settings))) {
+	if (!(cmd->cft_override = dm_config_from_string(config_settings))) {
 		log_error("Failed to set overridden configuration entries.");
 		return 1;
 	}
@@ -199,21 +51,16 @@
 	return 0;
 }
 
-int read_config_fd(struct config_tree *cft, struct device *dev,
+int read_config_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)
 {
-	struct cs *c = (struct cs *) cft;
-	struct parser *p;
+	const char *fb, *fe;
 	int r = 0;
 	int use_mmap = 1;
 	off_t mmap_offset = 0;
 	char *buf = NULL;
 
-	if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
-		return_0;
-	p->mem = c->mem;
-
 	/* Only use mmap with regular files */
 	if (!(dev->flags & DEV_REGULAR) || size2)
 		use_mmap = 0;
@@ -221,13 +68,13 @@
 	if (use_mmap) {
 		mmap_offset = offset % lvm_getpagesize();
 		/* memory map the file */
-		p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
-			     MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
-		if (p->fb == (caddr_t) (-1)) {
+		fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
+			  MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
+		if (fb == (caddr_t) (-1)) {
 			log_sys_error("mmap", dev_name(dev));
 			goto out;
 		}
-		p->fb = p->fb + mmap_offset;
+		fb = fb + mmap_offset;
 	} else {
 		if (!(buf = dm_malloc(size + size2)))
 			return_0;
@@ -235,19 +82,18 @@
 				       (uint64_t) offset2, size2, buf)) {
 			goto out;
 		}
-		p->fb = buf;
+		fb = buf;
 	}
 
 	if (checksum_fn && checksum !=
-	    (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)p->fb, size),
-			 (const uint8_t *)(p->fb + size), size2))) {
+	    (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
+			 (const uint8_t *)(fb + size), size2))) {
 		log_error("%s: Checksum error", dev_name(dev));
 		goto out;
 	}
 
-	p->fe = p->fb + size + size2;
-
-	if (!_parse_config_file(p, cft))
+	fe = fb + size + size2;
+	if (!dm_config_parse(cft, fb, fe))
 		goto_out;
 
 	r = 1;
@@ -257,7 +103,7 @@
 		dm_free(buf);
 	else {
 		/* unmap the file */
-		if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
+		if (munmap((char *) (fb - mmap_offset), size + mmap_offset)) {
 			log_sys_error("munmap", dev_name(dev));
 			r = 0;
 		}
@@ -266,906 +112,85 @@
 	return r;
 }
 
-int read_config_file(struct config_tree *cft)
+int read_config_file(struct dm_config_tree *cft)
 {
-	struct cs *c = (struct cs *) cft;
+	const char *filename;
+	struct device *dev = dm_config_get_custom(cft);
 	struct stat info;
-	int r = 1;
-
-	if (stat(c->filename, &info)) {
-		log_sys_error("stat", c->filename);
-		c->exists = 0;
-		return 0;
-	}
+	int r;
 
-	if (!S_ISREG(info.st_mode)) {
-		log_error("%s is not a regular file", c->filename);
-		c->exists = 0;
+	if (!dm_config_check_file(cft, &filename, &info))
 		return 0;
-	}
-
-	c->exists = 1;
-
-	if (info.st_size == 0) {
-		log_verbose("%s is empty", c->filename);
-		return 1;
-	}
 
-	if (!c->dev) {
-		if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
+	if (!dev) {
+		if (!(dev = dev_create_file(filename, NULL, NULL, 1)))
 			return_0;
 
-		if (!dev_open_readonly_buffered(c->dev)) {
-			c->dev = 0;
+		if (!dev_open_readonly_buffered(dev))
 			return_0;
-		}
 	}
 
-	r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
+	dm_config_set_custom(cft, dev);
+	r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0,
 			   (checksum_fn_t) NULL, 0);
 
-	if (!c->keep_open) {
-		dev_close(c->dev);
-		c->dev = 0;
+	if (!dm_config_keep_open(cft)) {
+		dev_close(dev);
+		dm_config_set_custom(cft, NULL);
 	}
 
-	c->timestamp = info.st_ctime;
-	c->st_size = info.st_size;
-
 	return r;
 }
 
-time_t config_file_timestamp(struct config_tree *cft)
-{
-	struct cs *c = (struct cs *) cft;
-
-	return c->timestamp;
-}
-
-/*
- * Return 1 if config files ought to be reloaded
- */
-int config_file_changed(struct config_tree *cft)
-{
-	struct cs *c = (struct cs *) cft;
-	struct stat info;
-
-	if (!c->filename)
-		return 0;
-
-	if (stat(c->filename, &info) == -1) {
-		/* Ignore a deleted config file: still use original data */
-		if (errno == ENOENT) {
-			if (!c->exists)
-				return 0;
-			log_very_verbose("Config file %s has disappeared!",
-					 c->filename);
-			goto reload;
-		}
-		log_sys_error("stat", c->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",
-			  c->filename);
-		goto reload;
-	}
-
-	/* Unchanged? */
-	if (c->timestamp == info.st_ctime && c->st_size == info.st_size)
-		return 0;
-
-      reload:
-	log_verbose("Detected config file change to %s", c->filename);
-	return 1;
-}
-
-static int _line_start(struct output_line *outline)
-{
-	if (!dm_pool_begin_object(outline->mem, 128)) {
-		log_error("dm_pool_begin_object failed for config line");
-		return 0;
-	}
-
-	return 1;
-}
-
-static int _line_append(struct output_line *outline, const char *fmt, ...)
-  __attribute__ ((format(printf, 2, 3)));
-static int _line_append(struct output_line *outline, const char *fmt, ...)
-{
-	char buf[4096];
-	va_list ap;
-	int n;
-
-	va_start(ap, fmt);
-	n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
-	va_end(ap);
-
-	if (n < 0 || n > (int) sizeof buf - 1) {
-		log_error("vsnprintf failed for config line");
-		return 0;
-	}
-
-	if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
-		log_error("dm_pool_grow_object failed for config line");
-		return 0;
-	}
-
-	return 1;
-}
-
-#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
-
-static int _line_end(struct output_line *outline)
-{
-	const char *line;
-
-	if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
-		log_error("dm_pool_grow_object failed for config line");
-		return 0;
-	}
-
-	line = dm_pool_end_object(outline->mem);
-	if (outline->putline)
-		outline->putline(line, outline->putline_baton);
-	else {
-		if (!outline->fp)
-			log_print("%s", line);
-		else
-			fprintf(outline->fp, "%s\n", line);
-	}
-
-	return 1;
-}
-
-static int _write_value(struct output_line *outline, const struct config_value *v)
-{
-	char *buf;
-
-	switch (v->type) {
-	case CFG_STRING:
-		if (!(buf = alloca(escaped_len(v->v.str)))) {
-			log_error("temporary stack allocation for a config "
-				  "string failed");
-			return 0;
-		}
-		line_append("\"%s\"", escape_double_quotes(buf, v->v.str));
-		break;
-
-	case CFG_FLOAT:
-		line_append("%f", v->v.r);
-		break;
-
-	case CFG_INT:
-		line_append("%" PRId64, v->v.i);
-		break;
-
-	case CFG_EMPTY_ARRAY:
-		line_append("[]");
-		break;
-
-	default:
-		log_error("_write_value: Unknown value type: %d", v->type);
-
-	}
-
-	return 1;
-}
-
-static int _write_config(const struct config_node *n, int only_one,
-			 struct output_line *outline, int level)
-{
-	char space[MAX_INDENT + 1];
-	int l = (level < MAX_INDENT) ? level : MAX_INDENT;
-	int i;
-
-	if (!n)
-		return 1;
-
-	for (i = 0; i < l; i++)
-		space[i] = '\t';
-	space[i] = '\0';
-
-	do {
-		if (!_line_start(outline))
-			return_0;
-		line_append("%s%s", space, n->key);
-		if (!n->v) {
-			/* it's a sub section */
-			line_append(" {");
-			if (!_line_end(outline))
-				return_0;
-			_write_config(n->child, 0, outline, level + 1);
-			if (!_line_start(outline))
-				return_0;
-			line_append("%s}", space);
-		} else {
-			/* it's a value */
-			const struct config_value *v = n->v;
-			line_append("=");
-			if (v->next) {
-				line_append("[");
-				while (v && v->type != CFG_EMPTY_ARRAY) {
-					if (!_write_value(outline, v))
-						return_0;
-					v = v->next;
-					if (v && v->type != CFG_EMPTY_ARRAY)
-						line_append(", ");
-				}
-				line_append("]");
-			} else
-				if (!_write_value(outline, v))
-					return_0;
-		}
-		if (!_line_end(outline))
-			return_0;
-		n = n->sib;
-	} while (n && !only_one);
-	/* FIXME: add error checking */
-	return 1;
-}
-
-int write_config_node(const struct config_node *cn, putline_fn putline, void *baton)
-{
-	struct output_line outline;
-	outline.fp = NULL;
-	if (!(outline.mem = dm_pool_create("config_line", 1024)))
-		return_0;
-	outline.putline = putline;
-	outline.putline_baton = baton;
-	if (!_write_config(cn, 0, &outline, 0)) {
-		dm_pool_destroy(outline.mem);
-		return_0;
-	}
-	dm_pool_destroy(outline.mem);
-	return 1;
-}
-
-int write_config_file(struct config_tree *cft, const char *file,
-		      int argc, char **argv)
+static struct dm_config_tree *_setup_context_tree(struct cmd_context *cmd)
 {
-	const struct config_node *cn;
-	int r = 1;
-	struct output_line outline;
-	outline.fp = NULL;
-	outline.putline = NULL;
-
-	if (!file)
-		file = "stdout";
-	else if (!(outline.fp = fopen(file, "w"))) {
-		log_sys_error("open", file);
-		return 0;
-	}
-
-	if (!(outline.mem = dm_pool_create("config_line", 1024))) {
-		r = 0;
-		goto_out;
-	}
-
-	log_verbose("Dumping configuration to %s", file);
-	if (!argc) {
-		if (!_write_config(cft->root, 0, &outline, 0)) {
-			log_error("Failure while writing to %s", file);
-			r = 0;
-		}
-	} else while (argc--) {
-		if ((cn = find_config_node(cft->root, *argv))) {
-			if (!_write_config(cn, 1, &outline, 0)) {
-				log_error("Failure while writing to %s", file);
-				r = 0;
-			}
-		} else {
-			log_error("Configuration node %s not found", *argv);
-			r = 0;
-		}
-		argv++;
-	}
+	struct dm_config_tree *r = cmd->cft_override;
 
-	dm_pool_destroy(outline.mem);
-
-out:
-	if (outline.fp && lvm_fclose(outline.fp, file)) {
-		stack;
-		r = 0;
-	}
+	if (r)
+		r->cascade = cmd->cft;
+	else
+		r = cmd->cft;
 
 	return r;
 }
 
-/*
- * parser
- */
-static struct config_node *_file(struct parser *p)
-{
-	struct config_node *root = NULL, *n, *l = NULL;
-	while (p->t != TOK_EOF) {
-		if (!(n = _section(p)))
-			return_0;
-
-		if (!root)
-			root = n;
-		else
-			l->sib = n;
-		n->parent = root;
-		l = n;
-	}
-	return root;
-}
-
-static struct config_node *_section(struct parser *p)
-{
-	/* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
-	struct config_node *root, *n, *l = NULL;
-	if (!(root = _create_node(p->mem)))
-		return_0;
-
-	if (!(root->key = _dup_tok(p)))
-		return_0;
-
-	match(TOK_IDENTIFIER);
-
-	if (p->t == TOK_SECTION_B) {
-		match(TOK_SECTION_B);
-		while (p->t != TOK_SECTION_E) {
-			if (!(n = _section(p)))
-				return_0;
-
-			if (!root->child)
-				root->child = n;
-			else
-				l->sib = n;
-			n->parent = root;
-			l = n;
-		}
-		match(TOK_SECTION_E);
-	} else {
-		match(TOK_EQ);
-		if (!(root->v = _value(p)))
-			return_0;
-	}
-
-	return root;
-}
-
-static struct config_value *_value(struct parser *p)
-{
-	/* '[' TYPE* ']' | TYPE */
-	struct config_value *h = NULL, *l, *ll = NULL;
-	if (p->t == TOK_ARRAY_B) {
-		match(TOK_ARRAY_B);
-		while (p->t != TOK_ARRAY_E) {
-			if (!(l = _type(p)))
-				return_0;
-
-			if (!h)
-				h = l;
-			else
-				ll->next = l;
-			ll = l;
-
-			if (p->t == TOK_COMMA)
-				match(TOK_COMMA);
-		}
-		match(TOK_ARRAY_E);
-		/*
-		 * Special case for an empty array.
-		 */
-		if (!h) {
-			if (!(h = _create_value(p->mem)))
-				return NULL;
-
-			h->type = CFG_EMPTY_ARRAY;
-		}
-
-	} else
-		h = _type(p);
-
-	return h;
-}
-
-static struct config_value *_type(struct parser *p)
-{
-	/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
-	struct config_value *v = _create_value(p->mem);
-	char *str;
-
-	if (!v)
-		return NULL;
-
-	switch (p->t) {
-	case TOK_INT:
-		v->type = CFG_INT;
-		v->v.i = strtoll(p->tb, NULL, 0);	/* FIXME: check error */
-		match(TOK_INT);
-		break;
-
-	case TOK_FLOAT:
-		v->type = CFG_FLOAT;
-		v->v.r = strtod(p->tb, NULL);	/* FIXME: check error */
-		match(TOK_FLOAT);
-		break;
-
-	case TOK_STRING:
-		v->type = CFG_STRING;
-
-		p->tb++, p->te--;	/* strip "'s */
-		if (!(v->v.str = _dup_tok(p)))
-			return_0;
-		p->te++;
-		match(TOK_STRING);
-		break;
-
-	case TOK_STRING_ESCAPED:
-		v->type = CFG_STRING;
-
-		p->tb++, p->te--;	/* strip "'s */
-		if (!(str = _dup_tok(p)))
-			return_0;
-		unescape_double_quotes(str);
-		v->v.str = str;
-		p->te++;
-		match(TOK_STRING_ESCAPED);
-		break;
-
-	default:
-		log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
-			  p->tb - p->fb + 1, p->line);
-		return 0;
-	}
-	return v;
-}
-
-static int _match_aux(struct parser *p, int t)
-{
-	if (p->t != t)
-		return 0;
-
-	_get_token(p, t);
-	return 1;
-}
-
-/*
- * tokeniser
- */
-static void _get_token(struct parser *p, int tok_prev)
-{
-	int values_allowed = 0;
-
-	const char *te;
-
-	p->tb = p->te;
-	_eat_space(p);
-	if (p->tb == p->fe || !*p->tb) {
-		p->t = TOK_EOF;
-		return;
-	}
-
-	/* Should next token be interpreted as value instead of identifier? */
-	if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
-	    tok_prev == TOK_COMMA)
-		values_allowed = 1;
-
-	p->t = TOK_INT;		/* fudge so the fall through for
-				   floats works */
-
-	te = p->te;
-	switch (*te) {
-	case SECTION_B_CHAR:
-		p->t = TOK_SECTION_B;
-		te++;
-		break;
-
-	case SECTION_E_CHAR:
-		p->t = TOK_SECTION_E;
-		te++;
-		break;
-
-	case '[':
-		p->t = TOK_ARRAY_B;
-		te++;
-		break;
-
-	case ']':
-		p->t = TOK_ARRAY_E;
-		te++;
-		break;
-
-	case ',':
-		p->t = TOK_COMMA;
-		te++;
-		break;
-
-	case '=':
-		p->t = TOK_EQ;
-		te++;
-		break;
-
-	case '"':
-		p->t = TOK_STRING_ESCAPED;
-		te++;
-		while ((te != p->fe) && (*te) && (*te != '"')) {
-			if ((*te == '\\') && (te + 1 != p->fe) &&
-			    *(te + 1))
-				te++;
-			te++;
-		}
-
-		if ((te != p->fe) && (*te))
-			te++;
-		break;
-
-	case '\'':
-		p->t = TOK_STRING;
-		te++;
-		while ((te != p->fe) && (*te) && (*te != '\''))
-			te++;
-
-		if ((te != p->fe) && (*te))
-			te++;
-		break;
-
-	case '.':
-		p->t = TOK_FLOAT;
-		/* Fall through */
-	case '0':
-	case '1':
-	case '2':
-	case '3':
-	case '4':
-	case '5':
-	case '6':
-	case '7':
-	case '8':
-	case '9':
-	case '+':
-	case '-':
-		if (values_allowed) {
-			while (++te != p->fe) {
-				if (!isdigit((int) *te)) {
-					if (*te == '.') {
-						if (p->t != TOK_FLOAT) {
-							p->t = TOK_FLOAT;
-							continue;
-						}
-					}
-					break;
-				}
-			}
-			break;
-		}
-		/* fall through */
-
-	default:
-		p->t = TOK_IDENTIFIER;
-		while ((te != p->fe) && (*te) && !isspace(*te) &&
-		       (*te != '#') && (*te != '=') &&
-		       (*te != SECTION_B_CHAR) &&
-		       (*te != SECTION_E_CHAR))
-			te++;
-		break;
-	}
-
-	p->te = te;
-}
-
-static void _eat_space(struct parser *p)
-{
-	while (p->tb != p->fe) {
-		if (*p->te == '#')
-			while ((p->te != p->fe) && (*p->te != '\n') && (*p->te))
-				++p->te;
-
-		else if (!isspace(*p->te))
-			break;
-
-		while ((p->te != p->fe) && isspace(*p->te)) {
-			if (*p->te == '\n')
-				++p->line;
-			++p->te;
-		}
-
-		p->tb = p->te;
-	}
-}
-
-/*
- * memory management
- */
-static struct config_value *_create_value(struct dm_pool *mem)
-{
-	return dm_pool_zalloc(mem, sizeof(struct config_value));
-}
-
-static struct config_node *_create_node(struct dm_pool *mem)
-{
-	return dm_pool_zalloc(mem, sizeof(struct config_node));
-}
-
-static char *_dup_tok(struct parser *p)
-{
-	size_t len = p->te - p->tb;
-	char *str = dm_pool_alloc(p->mem, len + 1);
-	if (!str) {
-		log_error("Failed to duplicate token.");
-		return 0;
-	}
-	memcpy(str, p->tb, len);
-	str[len] = '\0';
-	return str;
-}
-
-/*
- * utility functions
- */
-static const struct config_node *_find_config_node(const struct config_node *cn,
+const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd,
 						   const char *path)
 {
-	const char *e;
-	const struct config_node *cn_found = NULL;
-
-	while (cn) {
-		/* trim any leading slashes */
-		while (*path && (*path == sep))
-			path++;
-
-		/* find the end of this segment */
-		for (e = path; *e && (*e != sep); e++) ;
-
-		/* hunt for the node */
-		cn_found = NULL;
-		while (cn) {
-			if (_tok_match(cn->key, path, e)) {
-				/* Inefficient */
-				if (!cn_found)
-					cn_found = cn;
-				else
-					log_warn("WARNING: Ignoring duplicate"
-						 " config node: %s ("
-						 "seeking %s)", cn->key, path);
-			}
-
-			cn = cn->sib;
-		}
-
-		if (cn_found && *e)
-			cn = cn_found->child;
-		else
-			break;	/* don't move into the last node */
-
-		path = e;
-	}
-
-	return cn_found;
-}
-
-static const struct config_node *_find_first_config_node(const struct config_node *cn1,
-							 const struct config_node *cn2,
-							 const char *path)
-{
-	const struct config_node *cn;
-
-	if (cn1 && (cn = _find_config_node(cn1, path)))
-		return cn;
-
-	if (cn2 && (cn = _find_config_node(cn2, path)))
-		return cn;
-
-	return NULL;
-}
-
-const struct config_node *find_config_node(const struct config_node *cn,
-					   const char *path)
-{
-	return _find_config_node(cn, path);
-}
-
-static const char *_find_config_str(const struct config_node *cn1,
-				    const struct config_node *cn2,
-				    const char *path, const char *fail)
-{
-	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
-	/* Empty strings are ignored */
-	if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
-		log_very_verbose("Setting %s to %s", path, n->v->v.str);
-		return n->v->v.str;
-	}
-
-	if (fail)
-		log_very_verbose("%s not found in config: defaulting to %s",
-				 path, fail);
-	return fail;
-}
-
-const char *find_config_str(const struct config_node *cn,
-			    const char *path, const char *fail)
-{
-	return _find_config_str(cn, NULL, path, fail);
-}
-
-static int64_t _find_config_int64(const struct config_node *cn1,
-				  const struct config_node *cn2,
-				  const char *path, int64_t fail)
-{
-	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
-	if (n && n->v && n->v->type == CFG_INT) {
-		log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
-		return n->v->v.i;
-	}
-
-	log_very_verbose("%s not found in config: defaulting to %" PRId64,
-			 path, fail);
-	return fail;
-}
-
-int find_config_int(const struct config_node *cn, const char *path, int fail)
-{
-	/* FIXME Add log_error message on overflow */
-	return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
-}
-
-static float _find_config_float(const struct config_node *cn1,
-				const struct config_node *cn2,
-				const char *path, float fail)
-{
-	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
-	if (n && n->v && n->v->type == CFG_FLOAT) {
-		log_very_verbose("Setting %s to %f", path, n->v->v.r);
-		return n->v->v.r;
-	}
-
-	log_very_verbose("%s not found in config: defaulting to %f",
-			 path, fail);
-
-	return fail;
-
-}
-
-float find_config_float(const struct config_node *cn, const char *path,
-			float fail)
-{
-	return _find_config_float(cn, NULL, path, fail);
-}
-
-const struct config_node *find_config_tree_node(struct cmd_context *cmd,
-					  const char *path)
-{
-	return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
+	return dm_config_tree_find_node(_setup_context_tree(cmd), path);
 }
 
 const char *find_config_tree_str(struct cmd_context *cmd,
 				 const char *path, const char *fail)
 {
-	return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
+	return dm_config_tree_find_str(_setup_context_tree(cmd), path, fail);
 }
 
 int find_config_tree_int(struct cmd_context *cmd, const char *path,
 			 int fail)
 {
-	/* FIXME Add log_error message on overflow */
-	return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
+	return dm_config_tree_find_int(_setup_context_tree(cmd), path, fail);
 }
 
 int64_t find_config_tree_int64(struct cmd_context *cmd, const char *path, int64_t fail)
 {
-	return _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL,
-				  cmd->cft->root, path, fail);
+	return dm_config_tree_find_int64(_setup_context_tree(cmd), path, fail);
 }
 
 float find_config_tree_float(struct cmd_context *cmd, const char *path,
 			     float fail)
 {
-	return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
-}
-
-static int _str_in_array(const char *str, const char * const values[])
-{
-	int i;
-
-	for (i = 0; values[i]; i++)
-		if (!strcasecmp(str, values[i]))
-			return 1;
-
-	return 0;
-}
-
-static int _str_to_bool(const char *str, int fail)
-{
-	const char * const _true_values[]  = { "y", "yes", "on", "true", NULL };
-	const char * const _false_values[] = { "n", "no", "off", "false", NULL };
-
-	if (_str_in_array(str, _true_values))
-		return 1;
-
-	if (_str_in_array(str, _false_values))
-		return 0;
-
-	return fail;
-}
-
-static int _find_config_bool(const struct config_node *cn1,
-			     const struct config_node *cn2,
-			     const char *path, int fail)
-{
-	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-	const struct config_value *v;
-
-	if (!n)
-		return fail;
-
-	v = n->v;
-
-	switch (v->type) {
-	case CFG_INT:
-		return v->v.i ? 1 : 0;
-
-	case CFG_STRING:
-		return _str_to_bool(v->v.str, fail);
-	}
-
-	return fail;
-}
-
-int find_config_bool(const struct config_node *cn, const char *path, int fail)
-{
-	return _find_config_bool(cn, NULL, path, fail);
+	return dm_config_tree_find_float(_setup_context_tree(cmd), path, fail);
 }
 
 int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
 {
-	return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
-}
-
-int get_config_uint32(const struct config_node *cn, const char *path,
-		      uint32_t *result)
-{
-	const struct config_node *n;
-
-	n = find_config_node(cn, path);
-
-	if (!n || !n->v || n->v->type != CFG_INT)
-		return 0;
-
-	*result = n->v->v.i;
-	return 1;
-}
-
-int get_config_uint64(const struct config_node *cn, const char *path,
-		      uint64_t *result)
-{
-	const struct config_node *n;
-
-	n = find_config_node(cn, path);
-
-	if (!n || !n->v || n->v->type != CFG_INT)
-		return 0;
-
-	*result = (uint64_t) n->v->v.i;
-	return 1;
-}
-
-int get_config_str(const struct config_node *cn, const char *path,
-		   const char **result)
-{
-	const struct config_node *n;
-
-	n = find_config_node(cn, path);
-
-	if (!n || !n->v || n->v->type != CFG_STRING)
-		return 0;
-
-	*result = n->v->v.str;
-	return 1;
+	return dm_config_tree_find_bool(_setup_context_tree(cmd), path, fail);
 }
 
 /* Insert cn2 after cn1 */
-static void _insert_config_node(struct config_node **cn1,
-				struct config_node *cn2)
+static void _insert_config_node(struct dm_config_node **cn1,
+				struct dm_config_node *cn2)
 {
 	if (!*cn1) {
 		*cn1 = cn2;
@@ -1180,10 +205,10 @@
  * Merge section cn2 into section cn1 (which has the same name)
  * overwriting any existing cn1 nodes with matching names.
  */
-static void _merge_section(struct config_node *cn1, struct config_node *cn2)
+static void _merge_section(struct dm_config_node *cn1, struct dm_config_node *cn2)
 {
-	struct config_node *cn, *nextn, *oldn;
-	struct config_value *cv;
+	struct dm_config_node *cn, *nextn, *oldn;
+	struct dm_config_value *cv;
 
 	for (cn = cn2->child; cn; cn = nextn) {
 		nextn = cn->sib;
@@ -1197,7 +222,7 @@
 			/* Ignore - we don't have any of these yet */
 			continue;
 		/* Not already present? */
-		if (!(oldn = (struct config_node*)find_config_node(cn1->child, cn->key))) {
+		if (!(oldn = (struct dm_config_node*)dm_config_find_node(cn1->child, cn->key))) {
 			_insert_config_node(&cn1->child, cn);
 			continue;
 		}
@@ -1217,13 +242,13 @@
 	}
 }
 
-static int _match_host_tags(struct dm_list *tags, const struct config_node *tn)
+static int _match_host_tags(struct dm_list *tags, const struct dm_config_node *tn)
 {
-	const struct config_value *tv;
+	const struct dm_config_value *tv;
 	const char *str;
 
 	for (tv = tn->v; tv; tv = tv->next) {
-		if (tv->type != CFG_STRING)
+		if (tv->type != DM_CFG_STRING)
 			continue;
 		str = tv->v.str;
 		if (*str == '@')
@@ -1238,12 +263,12 @@
 }
 
 /* Destructively merge a new config tree into an existing one */
-int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
-		      struct config_tree *newdata)
+int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
+		      struct dm_config_tree *newdata)
 {
-	const struct config_node *root = cft->root;
-	struct config_node *cn, *nextn, *oldn, *cn2;
-	const struct config_node *tn;
+	const struct dm_config_node *root = cft->root;
+	struct dm_config_node *cn, *nextn, *oldn, *cn2;
+	const struct dm_config_node *tn;
 
 	for (cn = newdata->root; cn; cn = nextn) {
 		nextn = cn->sib;
@@ -1251,11 +276,11 @@
 		if (!strcmp(cn->key, "tags"))
 			continue;
 		/* If there's a tags node, skip if host tags don't match */
-		if ((tn = find_config_node(cn->child, "tags"))) {
+		if ((tn = dm_config_find_node(cn->child, "tags"))) {
 			if (!_match_host_tags(&cmd->tags, tn))
 				continue;
 		}
-		if (!(oldn = (struct config_node *)find_config_node(root, cn->key))) {
+		if (!(oldn = (struct dm_config_node *)dm_config_find_node(root, cn->key))) {
 			_insert_config_node(&cft->root, cn);
 			/* Remove any "tags" nodes */
 			for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
@@ -1276,159 +301,3 @@
 	return 1;
 }
 
-/*
- * Convert a token type to the char it represents.
- */
-static char _token_type_to_char(int type)
-{
-	switch (type) {
-		case TOK_SECTION_B:
-			return SECTION_B_CHAR;
-		case TOK_SECTION_E:
-			return SECTION_E_CHAR;
-		default:
-			return 0;
-	}
-}
-
-/*
- * Returns:
- *  # of 'type' tokens in 'str'.
- */
-static unsigned _count_tokens(const char *str, unsigned len, int type)
-{
-	char c;
-
-	c = _token_type_to_char(type);
-
-	return count_chars(str, len, c);
-}
-
-const char *config_parent_name(const struct config_node *n)
-{
-	return (n->parent ? n->parent->key : "(root)");
-}
-/*
- * Heuristic function to make a quick guess as to whether a text
- * region probably contains a valid config "section".  (Useful for
- * scanning areas of the disk for old metadata.)
- * Config sections contain various tokens, may contain other sections
- * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
- * end (type 'TOK_SECTION_E') tokens.  As a quick heuristic, we just
- * count the number of begin and end tokens, and see if they are
- * non-zero and the counts match.
- * Full validation of the section should be done with another function
- * (for example, read_config_fd).
- *
- * Returns:
- *  0 - probably is not a valid config section
- *  1 - probably _is_ a valid config section
- */
-unsigned maybe_config_section(const char *str, unsigned len)
-{
-	int begin_count;
-	int end_count;
-
-	begin_count = _count_tokens(str, len, TOK_SECTION_B);
-	end_count = _count_tokens(str, len, TOK_SECTION_E);
-
-	if (begin_count && end_count && (begin_count == end_count))
-		return 1;
-	else
-		return 0;
-}
-
-static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
-{
-	struct config_value *new_cv;
-
-	if (!v)
-		return NULL;
-
-	if (!(new_cv = _create_value(mem))) {
-		log_error("Failed to clone config value.");
-		return NULL;
-	}
-
-	new_cv->type = v->type;
-	if (v->type == CFG_STRING) {
-		if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
-			log_error("Failed to clone config string value.");
-			return NULL;
-		}
-	} else
-		new_cv->v = v->v;
-
-	if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
-		return_NULL;
-
-	return new_cv;
-}
-
-struct config_node *clone_config_node_with_mem(struct dm_pool *mem, const struct config_node *cn,
-					       int siblings)
-{
-	struct config_node *new_cn;
-
-	if (!cn)
-		return NULL;
-
-	if (!(new_cn = _create_node(mem))) {
-		log_error("Failed to clone config node.");
-		return NULL;
-	}
-
-	if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
-		log_error("Failed to clone config node key.");
-		return NULL;
-	}
-
-	if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
-	    (cn->child && !(new_cn->child = clone_config_node_with_mem(mem, cn->child, 1))) ||
-	    (siblings && cn->sib && !(new_cn->sib = clone_config_node_with_mem(mem, cn->sib, siblings))))
-		return_NULL; /* 'new_cn' released with mem pool */
-
-	return new_cn;
-}
-
-struct config_node *clone_config_node(struct config_tree *cft, const struct config_node *node, int sib)
-{
-	struct cs *c = (struct cs *) cft;
-	return clone_config_node_with_mem(c->mem, node, sib);
-}
-
-struct config_node *create_config_node(struct config_tree *cft, const char *key)
-{
-	struct cs *c = (struct cs *) cft;
-	struct config_node *cn;
-
-	if (!(cn = _create_node(c->mem))) {
-		log_error("Failed to create config node.");
-		return NULL;
-	}
-	if (!(cn->key = dm_pool_strdup(c->mem, key))) {
-		log_error("Failed to create config node's key.");
-		return NULL;
-	}
-	if (!(cn->v = _create_value(c->mem))) {
-		log_error("Failed to create config node's value.");
-		return NULL;
-	}
-	cn->parent = NULL;
-	cn->v->type = CFG_INT;
-	cn->v->v.i = 0;
-	cn->v->next = NULL;
-	return cn;
-}
-
-struct config_value *create_config_value(struct config_tree *cft)
-{
-	struct cs *c = (struct cs *) cft;
-	return _create_value(c->mem);
-}
-
-struct dm_pool *config_tree_memory(struct config_tree *cft)
-{
-	struct cs *c = (struct cs *) cft;
-	return c->mem;
-}
diff -ruN -xCVS cvs-clean/lib/config/config.h cvs-daemons-reorg/lib/config/config.h
--- cvs-clean/lib/config/config.h	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/config/config.h	2011-08-29 19:41:48.000000000 +0200
@@ -21,76 +21,26 @@
 struct device;
 struct cmd_context;
 
-enum {
-	CFG_STRING,
-	CFG_FLOAT,
-	CFG_INT,
-	CFG_EMPTY_ARRAY
-};
-
-struct config_value {
-	int type;
-	union {
-		int64_t i;
-		float r;
-		const char *str;
-	} v;
-	struct config_value *next;	/* for arrays */
-};
-
-struct config_node {
-	const char *key;
-	struct config_node *parent, *sib, *child;
-	struct config_value *v;
-};
-
-struct config_tree {
-	struct config_node *root;
-};
-
-struct config_tree_list {
-	struct dm_list list;
-	struct config_tree *cft;
-};
-
-struct config_tree *create_config_tree(const char *filename, int keep_open);
-struct config_tree *create_config_tree_from_string(const char *config_settings);
-
 int override_config_tree_from_string(struct cmd_context *cmd,
 				     const char *config_settings);
-void destroy_config_tree(struct config_tree *cft);
+void destroy_config_tree(struct dm_config_tree *cft);
 
 typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_t size);
 
-int read_config_fd(struct config_tree *cft, struct device *dev,
+int read_config_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);
 
-int read_config_file(struct config_tree *cft);
-int write_config_file(struct config_tree *cft, const char *file,
-		      int argc, char **argv);
-
-typedef int (*putline_fn)(const char *line, void *baton);
-int write_config_node(const struct config_node *cn, putline_fn putline, void *baton);
-
-time_t config_file_timestamp(struct config_tree *cft);
-int config_file_changed(struct config_tree *cft);
-int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
-		      struct config_tree *newdata);
-
-const struct config_node *find_config_node(const struct config_node *cn,
-					   const char *path);
-const char *find_config_str(const struct config_node *cn, const char *path,
-			    const char *fail);
-int find_config_int(const struct config_node *cn, const char *path, int fail);
-float find_config_float(const struct config_node *cn, const char *path,
-			float fail);
+int read_config_file(struct dm_config_tree *cft);
+
+int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
+		      struct dm_config_tree *newdata);
 
 /*
  * These versions check an override tree, if present, first.
  */
-const struct config_node *find_config_tree_node(struct cmd_context *cmd,
-						const char *path);
+const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd,
+						   const char *path);
 const char *find_config_tree_str(struct cmd_context *cmd,
 				 const char *path, const char *fail);
 int find_config_tree_int(struct cmd_context *cmd, const char *path,
@@ -100,34 +50,6 @@
 float find_config_tree_float(struct cmd_context *cmd, const char *path,
 			     float fail);
 
-/*
- * Understands (0, ~0), (y, n), (yes, no), (on,
- * off), (true, false).
- */
-int find_config_bool(const struct config_node *cn, const char *path, int fail);
 int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail);
 
-int get_config_uint32(const struct config_node *cn, const char *path,
-		      uint32_t *result);
-
-int get_config_uint64(const struct config_node *cn, const char *path,
-		      uint64_t *result);
-
-int get_config_str(const struct config_node *cn, const char *path,
-		   const char **result);
-
-unsigned maybe_config_section(const char *str, unsigned len);
-
-const char *config_parent_name(const struct config_node *n);
-
-struct config_node *clone_config_node_with_mem(struct dm_pool *mem,
-					       const struct config_node *node,
-					       int siblings);
-struct config_node *create_config_node(struct config_tree *cft, const char *key);
-struct config_value *create_config_value(struct config_tree *cft);
-struct config_node *clone_config_node(struct config_tree *cft, const struct config_node *cn,
-				      int siblings);
-
-struct dm_pool *config_tree_memory(struct config_tree *cft);
-
 #endif
diff -ruN -xCVS cvs-clean/lib/device/dev-cache.c cvs-daemons-reorg/lib/device/dev-cache.c
--- cvs-clean/lib/device/dev-cache.c	2011-05-07 15:05:52.000000000 +0200
+++ cvs-daemons-reorg/lib/device/dev-cache.c	2011-08-29 19:41:48.000000000 +0200
@@ -644,8 +644,8 @@
 
 static int _init_preferred_names(struct cmd_context *cmd)
 {
-	const struct config_node *cn;
-	const struct config_value *v;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *v;
 	struct dm_pool *scratch = NULL;
 	const char **regex;
 	unsigned count = 0;
@@ -654,14 +654,14 @@
 	_cache.preferred_names_matcher = NULL;
 
 	if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
-	    cn->v->type == CFG_EMPTY_ARRAY) {
+	    cn->v->type == DM_CFG_EMPTY_ARRAY) {
 		log_very_verbose("devices/preferred_names not found in config file: "
 				 "using built-in preferences");
 		return 1;
 	}
 
 	for (v = cn->v; v; v = v->next) {
-		if (v->type != CFG_STRING) {
+		if (v->type != DM_CFG_STRING) {
 			log_error("preferred_names patterns must be enclosed in quotes");
 			return 0;
 		}
diff -ruN -xCVS cvs-clean/lib/filters/filter.c cvs-daemons-reorg/lib/filters/filter.c
--- cvs-clean/lib/filters/filter.c	2011-06-15 14:30:22.000000000 +0200
+++ cvs-daemons-reorg/lib/filters/filter.c	2011-08-29 19:41:48.000000000 +0200
@@ -177,7 +177,7 @@
 	return ret;
 }
 
-static int _scan_proc_dev(const char *proc, const struct config_node *cn)
+static int _scan_proc_dev(const char *proc, const struct dm_config_node *cn)
 {
 	char line[80];
 	char proc_devices[PATH_MAX];
@@ -186,7 +186,7 @@
 	int line_maj = 0;
 	int blocksection = 0;
 	size_t dev_len = 0;
-	const struct config_value *cv;
+	const struct dm_config_value *cv;
 	const char *name;
 
 
@@ -269,7 +269,7 @@
 
 		/* Check devices/types for local variations */
 		for (cv = cn->v; cv; cv = cv->next) {
-			if (cv->type != CFG_STRING) {
+			if (cv->type != DM_CFG_STRING) {
 				log_error("Expecting string in devices/types "
 					  "in config file");
 				if (fclose(pd))
@@ -279,7 +279,7 @@
 			dev_len = strlen(cv->v.str);
 			name = cv->v.str;
 			cv = cv->next;
-			if (!cv || cv->type != CFG_INT) {
+			if (!cv || cv->type != DM_CFG_INT) {
 				log_error("Max partition count missing for %s "
 					  "in devices/types in config file",
 					  name);
@@ -316,7 +316,7 @@
 }
 
 struct dev_filter *lvm_type_filter_create(const char *proc,
-					  const struct config_node *cn)
+					  const struct dm_config_node *cn)
 {
 	struct dev_filter *f;
 
diff -ruN -xCVS cvs-clean/lib/filters/filter.h cvs-daemons-reorg/lib/filters/filter.h
--- cvs-clean/lib/filters/filter.h	2010-07-02 04:09:57.000000000 +0200
+++ cvs-daemons-reorg/lib/filters/filter.h	2011-08-29 19:41:48.000000000 +0200
@@ -31,7 +31,7 @@
 #endif
 
 struct dev_filter *lvm_type_filter_create(const char *proc,
-					  const struct config_node *cn);
+					  const struct dm_config_node *cn);
 
 void lvm_type_filter_destroy(struct dev_filter *f);
 
diff -ruN -xCVS cvs-clean/lib/filters/filter-persistent.c cvs-daemons-reorg/lib/filters/filter-persistent.c
--- cvs-clean/lib/filters/filter-persistent.c	2011-06-15 14:30:22.000000000 +0200
+++ cvs-daemons-reorg/lib/filters/filter-persistent.c	2011-08-29 19:41:48.000000000 +0200
@@ -64,13 +64,13 @@
 	return 1;
 }
 
-static int _read_array(struct pfilter *pf, struct config_tree *cft,
+static int _read_array(struct pfilter *pf, struct dm_config_tree *cft,
 		       const char *path, void *data)
 {
-	const struct config_node *cn;
-	const struct config_value *cv;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *cv;
 
-	if (!(cn = find_config_node(cft->root, path))) {
+	if (!(cn = dm_config_find_node(cft->root, path))) {
 		log_very_verbose("Couldn't find %s array in '%s'",
 				 path, pf->file);
 		return 0;
@@ -81,7 +81,7 @@
 	 * devices as we go.
 	 */
 	for (cv = cn->v; cv; cv = cv->next) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_verbose("Devices array contains a value "
 				    "which is not a string ... ignoring");
 			continue;
@@ -96,10 +96,10 @@
 	return 1;
 }
 
-int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
+int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out)
 {
 	struct pfilter *pf = (struct pfilter *) f->private;
-	struct config_tree *cft;
+	struct dm_config_tree *cft;
 	struct stat info;
 	int r = 0;
 
@@ -122,7 +122,7 @@
 		return_0;
 	}
 
-	if (!(cft = create_config_tree(pf->file, 1)))
+	if (!(cft = dm_config_create(pf->file, 1)))
 		return_0;
 
 	if (!read_config_file(cft))
@@ -173,7 +173,7 @@
 			first = 0;
 		}
 
-		escape_double_quotes(buf, dm_hash_get_key(pf->devices, n));
+		dm_escape_double_quotes(buf, dm_hash_get_key(pf->devices, n));
 		fprintf(fp, "\t\t\"%s\"", buf);
 	}
 
@@ -186,7 +186,7 @@
 	struct pfilter *pf;
 	char *tmp_file;
 	struct stat info, info2;
-	struct config_tree *cft = NULL;
+	struct dm_config_tree *cft = NULL;
 	FILE *fp;
 	int lockfd;
 	int r = 0;
diff -ruN -xCVS cvs-clean/lib/filters/filter-persistent.h cvs-daemons-reorg/lib/filters/filter-persistent.h
--- cvs-clean/lib/filters/filter-persistent.h	2010-05-13 15:04:05.000000000 +0200
+++ cvs-daemons-reorg/lib/filters/filter-persistent.h	2011-08-29 19:41:48.000000000 +0200
@@ -22,7 +22,7 @@
 					    const char *file);
 
 int persistent_filter_wipe(struct dev_filter *f);
-int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out);
+int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out);
 int persistent_filter_dump(struct dev_filter *f, int merge_existing);
 
 #endif
diff -ruN -xCVS cvs-clean/lib/filters/filter-regex.c cvs-daemons-reorg/lib/filters/filter-regex.c
--- cvs-clean/lib/filters/filter-regex.c	2011-02-18 15:47:30.000000000 +0100
+++ cvs-daemons-reorg/lib/filters/filter-regex.c	2011-08-29 19:41:48.000000000 +0200
@@ -87,10 +87,10 @@
 	return 1;
 }
 
-static int _build_matcher(struct rfilter *rf, const struct config_value *val)
+static int _build_matcher(struct rfilter *rf, const struct dm_config_value *val)
 {
 	struct dm_pool *scratch;
-	const struct config_value *v;
+	const struct dm_config_value *v;
 	char **regex;
 	unsigned count = 0;
 	int i, r = 0;
@@ -102,7 +102,7 @@
 	 * count how many patterns we have.
 	 */
 	for (v = val; v; v = v->next) {
-		if (v->type != CFG_STRING) {
+		if (v->type != DM_CFG_STRING) {
 			log_error("Filter patterns must be enclosed in quotes.");
 			goto out;
 		}
@@ -188,7 +188,7 @@
 	dm_pool_destroy(rf->mem);
 }
 
-struct dev_filter *regex_filter_create(const struct config_value *patterns)
+struct dev_filter *regex_filter_create(const struct dm_config_value *patterns)
 {
 	struct dm_pool *mem = dm_pool_create("filter regex", 10 * 1024);
 	struct rfilter *rf;
diff -ruN -xCVS cvs-clean/lib/filters/filter-regex.h cvs-daemons-reorg/lib/filters/filter-regex.h
--- cvs-clean/lib/filters/filter-regex.h	2010-12-20 14:12:56.000000000 +0100
+++ cvs-daemons-reorg/lib/filters/filter-regex.h	2011-08-29 19:41:48.000000000 +0200
@@ -27,6 +27,6 @@
  * r|.*|             - reject everything else
  */
 
-struct dev_filter *regex_filter_create(const struct config_value *patterns);
+struct dev_filter *regex_filter_create(const struct dm_config_value *patterns);
 
 #endif
diff -ruN -xCVS cvs-clean/lib/format_text/export.c cvs-daemons-reorg/lib/format_text/export.c
--- cvs-clean/lib/format_text/export.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/format_text/export.c	2011-08-29 19:41:48.000000000 +0200
@@ -319,9 +319,9 @@
 	return out_text(f, "%s", line);
 }
 
-int out_config_node(struct formatter *f, const struct config_node *cn)
+int out_config_node(struct formatter *f, const struct dm_config_node *cn)
 {
-	return write_config_node(cn, _out_line, f);
+	return dm_config_write_node(cn, _out_line, f);
 }
 
 static int _print_header(struct formatter *f,
@@ -337,12 +337,12 @@
 	outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
 	outnl(f);
 
-	if (!(buf = alloca(escaped_len(desc)))) {
+	if (!(buf = alloca(dm_escaped_len(desc)))) {
 		log_error("temporary stack allocation for description"
 			  "string failed");
 		return 0;
 	}
-	outf(f, "description = \"%s\"", escape_double_quotes(buf, desc));
+	outf(f, "description = \"%s\"", dm_escape_double_quotes(buf, desc));
 	outnl(f);
 	outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
 	     _utsname.sysname, _utsname.nodename, _utsname.release,
@@ -465,14 +465,14 @@
 
 		outf(f, "id = \"%s\"", buffer);
 
-		if (!(buf = alloca(escaped_len(pv_dev_name(pv))))) {
+		if (!(buf = alloca(dm_escaped_len(pv_dev_name(pv))))) {
 			log_error("temporary stack allocation for device name"
 				  "string failed");
 			return 0;
 		}
 
 		outhint(f, "device = \"%s\"",
-			escape_double_quotes(buf, pv_dev_name(pv)));
+			dm_escape_double_quotes(buf, pv_dev_name(pv)));
 		outnl(f);
 
 		if (!_print_flag_config(f, pv->status, PV_FLAGS))
diff -ruN -xCVS cvs-clean/lib/format_text/flags.c cvs-daemons-reorg/lib/format_text/flags.c
--- cvs-clean/lib/format_text/flags.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/format_text/flags.c	2011-08-29 19:41:48.000000000 +0200
@@ -140,7 +140,7 @@
 	return 1;
 }
 
-int read_flags(uint64_t *status, int type, const struct config_value *cv)
+int read_flags(uint64_t *status, int type, const struct dm_config_value *cv)
 {
 	int f;
 	uint64_t s = UINT64_C(0);
@@ -149,11 +149,11 @@
 	if (!(flags = _get_flags(type)))
 		return_0;
 
-	if (cv->type == CFG_EMPTY_ARRAY)
+	if (cv->type == DM_CFG_EMPTY_ARRAY)
 		goto out;
 
 	while (cv) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Status value is not a string.");
 			return 0;
 		}
diff -ruN -xCVS cvs-clean/lib/format_text/format-text.c cvs-daemons-reorg/lib/format_text/format-text.c
--- cvs-clean/lib/format_text/format-text.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/format_text/format-text.c	2011-08-29 19:41:48.000000000 +0200
@@ -223,7 +223,7 @@
 		 * area->start to area->start+area->size is not used.
 		 * Only ~32KB seems to contain valid metadata records
 		 * (LVM2 format - format_text).  As a result, I end up with
-		 * "maybe_config_section" returning true when there's no valid
+		 * "dm_config_maybe_section" returning true when there's no valid
 		 * metadata in a sector (sectors with all nulls).
 		 */
 		if (!(buf = dm_malloc(size + size2)))
@@ -236,7 +236,7 @@
 		/*
 		 * FIXME: We could add more sophisticated metadata detection
 		 */
-		if (maybe_config_section(buf, size + size2)) {
+		if (dm_config_maybe_section(buf, size + size2)) {
 			/* FIXME: Validate region, pull out timestamp?, etc */
 			/* FIXME: Do something with this region */
 			log_verbose ("Found LVM2 metadata record at "
@@ -2277,7 +2277,7 @@
 }
 
 static int _get_config_disk_area(struct cmd_context *cmd,
-				 const struct config_node *cn, struct dm_list *raw_list)
+				 const struct dm_config_node *cn, struct dm_list *raw_list)
 {
 	struct device_area dev_area;
 	const char *id_str;
@@ -2288,21 +2288,21 @@
 		return 0;
 	}
 
-	if (!get_config_uint64(cn, "start_sector", &dev_area.start)) {
+	if (!dm_config_get_uint64(cn, "start_sector", &dev_area.start)) {
 		log_error("Missing start_sector in metadata disk_area section "
 			  "of config file");
 		return 0;
 	}
 	dev_area.start <<= SECTOR_SHIFT;
 
-	if (!get_config_uint64(cn, "size", &dev_area.size)) {
+	if (!dm_config_get_uint64(cn, "size", &dev_area.size)) {
 		log_error("Missing size in metadata disk_area section "
 			  "of config file");
 		return 0;
 	}
 	dev_area.size <<= SECTOR_SHIFT;
 
-	if (!get_config_str(cn, "id", &id_str)) {
+	if (!dm_config_get_str(cn, "id", &id_str)) {
 		log_error("Missing uuid in metadata disk_area section "
 			  "of config file");
 		return 0;
@@ -2332,8 +2332,8 @@
 struct format_type *create_text_format(struct cmd_context *cmd)
 {
 	struct format_type *fmt;
-	const struct config_node *cn;
-	const struct config_value *cv;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *cv;
 	struct mda_lists *mda_lists;
 
 	if (!(fmt = dm_malloc(sizeof(*fmt))))
@@ -2374,7 +2374,7 @@
 
 	if ((cn = find_config_tree_node(cmd, "metadata/dirs"))) {
 		for (cv = cn->v; cv; cv = cv->next) {
-			if (cv->type != CFG_STRING) {
+			if (cv->type != DM_CFG_STRING) {
 				log_error("Invalid string in config file: "
 					  "metadata/dirs");
 				goto err;
diff -ruN -xCVS cvs-clean/lib/format_text/import.c cvs-daemons-reorg/lib/format_text/import.c
--- cvs-clean/lib/format_text/import.c	2011-07-11 12:45:19.000000000 +0200
+++ cvs-daemons-reorg/lib/format_text/import.c	2011-08-29 19:41:48.000000000 +0200
@@ -43,13 +43,13 @@
 			       struct id *vgid, uint64_t *vgstatus,
 			       char **creation_host)
 {
-	struct config_tree *cft;
+	struct dm_config_tree *cft;
 	struct text_vg_version_ops **vsn;
 	const char *vgname = NULL;
 
 	_init_text_import();
 
-	if (!(cft = create_config_tree(NULL, 0)))
+	if (!(cft = dm_config_create(NULL, 0)))
 		return_NULL;
 
 	if ((!dev && !read_config_file(cft)) ||
@@ -86,7 +86,7 @@
 				       time_t *when, char **desc)
 {
 	struct volume_group *vg = NULL;
-	struct config_tree *cft;
+	struct dm_config_tree *cft;
 	struct text_vg_version_ops **vsn;
 
 	_init_text_import();
@@ -94,7 +94,7 @@
 	*desc = NULL;
 	*when = 0;
 
-	if (!(cft = create_config_tree(file, 0)))
+	if (!(cft = dm_config_create(file, 0)))
 		return_NULL;
 
 	if ((!dev && !read_config_file(cft)) ||
@@ -131,7 +131,7 @@
 				 when, desc);
 }
 
-struct volume_group *import_vg_from_config_tree(const struct config_tree *cft,
+struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
 						struct format_instance *fid)
 {
 	struct volume_group *vg = NULL;
diff -ruN -xCVS cvs-clean/lib/format_text/import-export.h cvs-daemons-reorg/lib/format_text/import-export.h
--- cvs-clean/lib/format_text/import-export.h	2010-12-20 14:12:56.000000000 +0100
+++ cvs-daemons-reorg/lib/format_text/import-export.h	2011-08-29 19:41:48.000000000 +0200
@@ -44,14 +44,14 @@
 };
 
 struct text_vg_version_ops {
-	int (*check_version) (const struct config_tree * cf);
+	int (*check_version) (const struct dm_config_tree * cf);
 	struct volume_group *(*read_vg) (struct format_instance * fid,
-					 const struct config_tree *cf,
+					 const struct dm_config_tree *cf,
 					 unsigned use_cached_pvs);
-	void (*read_desc) (struct dm_pool * mem, const struct config_tree *cf,
+	void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
 			   time_t *when, char **desc);
 	const char *(*read_vgname) (const struct format_type *fmt,
-				    const struct config_tree *cft,
+				    const struct dm_config_tree *cft,
 				    struct id *vgid, uint64_t *vgstatus,
 				    char **creation_host);
 };
@@ -59,10 +59,10 @@
 struct text_vg_version_ops *text_vg_vsn1_init(void);
 
 int print_flags(uint64_t status, int type, char *buffer, size_t size);
-int read_flags(uint64_t *status, int type, const struct config_value *cv);
+int read_flags(uint64_t *status, int type, const struct dm_config_value *cv);
 
 char *alloc_printed_tags(struct dm_list *tags);
-int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct config_value *cv);
+int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv);
 
 int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
 int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
diff -ruN -xCVS cvs-clean/lib/format_text/import_vsn1.c cvs-daemons-reorg/lib/format_text/import_vsn1.c
--- cvs-clean/lib/format_text/import_vsn1.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/format_text/import_vsn1.c	2011-08-29 19:41:48.000000000 +0200
@@ -26,21 +26,21 @@
 #include "defaults.h"
 
 typedef int (*section_fn) (struct format_instance * fid, struct dm_pool * mem,
-			   struct volume_group * vg, const struct config_node * pvn,
-			   const struct config_node * vgn,
+			   struct volume_group * vg, const struct dm_config_node * pvn,
+			   const struct dm_config_node * vgn,
 			   struct dm_hash_table * pv_hash,
 			   struct dm_hash_table * lv_hash,
 			   unsigned *scan_done_once,
 			   unsigned report_missing_devices);
 
 #define _read_int32(root, path, result) \
-	get_config_uint32(root, path, (uint32_t *) result)
+	dm_config_get_uint32(root, path, (uint32_t *) result)
 
 #define _read_uint32(root, path, result) \
-	get_config_uint32(root, path, result)
+	dm_config_get_uint32(root, path, result)
 
 #define _read_int64(root, path, result) \
-	get_config_uint64(root, path, result)
+	dm_config_get_uint64(root, path, result)
 
 /*
  * Logs an attempt to read an invalid format file.
@@ -54,21 +54,21 @@
  * Checks that the config file contains vg metadata, and that it
  * we recognise the version number,
  */
-static int _vsn1_check_version(const struct config_tree *cft)
+static int _vsn1_check_version(const struct dm_config_tree *cft)
 {
-	const struct config_node *cn;
-	const struct config_value *cv;
+	const struct dm_config_node *cn;
+	const struct dm_config_value *cv;
 
 	/*
 	 * Check the contents field.
 	 */
-	if (!(cn = find_config_node(cft->root, CONTENTS_FIELD))) {
+	if (!(cn = dm_config_find_node(cft->root, CONTENTS_FIELD))) {
 		_invalid_format("missing contents field");
 		return 0;
 	}
 
 	cv = cn->v;
-	if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
+	if (!cv || cv->type != DM_CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
 		_invalid_format("unrecognised contents field");
 		return 0;
 	}
@@ -76,13 +76,13 @@
 	/*
 	 * Check the version number.
 	 */
-	if (!(cn = find_config_node(cft->root, FORMAT_VERSION_FIELD))) {
+	if (!(cn = dm_config_find_node(cft->root, FORMAT_VERSION_FIELD))) {
 		_invalid_format("missing version number");
 		return 0;
 	}
 
 	cv = cn->v;
-	if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
+	if (!cv || cv->type != DM_CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
 		_invalid_format("unrecognised version number");
 		return 0;
 	}
@@ -106,11 +106,11 @@
 	return 0;
 }
 
-static int _read_id(struct id *id, const struct config_node *cn, const char *path)
+static int _read_id(struct id *id, const struct dm_config_node *cn, const char *path)
 {
-	const struct config_value *cv;
+	const struct dm_config_value *cv;
 
-	if (!(cn = find_config_node(cn, path))) {
+	if (!(cn = dm_config_find_node(cn, path))) {
 		log_error("Couldn't find uuid.");
 		return 0;
 	}
@@ -129,12 +129,12 @@
 	return 1;
 }
 
-static int _read_flag_config(const struct config_node *n, uint64_t *status, int type)
+static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, int type)
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	*status = 0;
 
-	if (!(cn = find_config_node(n, "status"))) {
+	if (!(cn = dm_config_find_node(n, "status"))) {
 		log_error("Could not find status flags.");
 		return 0;
 	}
@@ -144,7 +144,7 @@
 		return 0;
 	}
 
-	if ((cn = find_config_node(n, "flags"))) {
+	if ((cn = dm_config_find_node(n, "flags"))) {
 		if (!(read_flags(status, type, cn->v))) {
 			log_error("Could not read flags.");
 			return 0;
@@ -155,8 +155,8 @@
 }
 
 static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
-		    struct volume_group *vg, const struct config_node *pvn,
-		    const struct config_node *vgn __attribute__((unused)),
+		    struct volume_group *vg, const struct dm_config_node *pvn,
+		    const struct dm_config_node *vgn __attribute__((unused)),
 		    struct dm_hash_table *pv_hash,
 		    struct dm_hash_table *lv_hash __attribute__((unused)),
 		    unsigned *scan_done_once,
@@ -164,7 +164,7 @@
 {
 	struct physical_volume *pv;
 	struct pv_list *pvl;
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	uint64_t size;
 
 	if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
@@ -238,7 +238,7 @@
 	dm_list_init(&pv->segments);
 
 	/* Optional tags */
-	if ((cn = find_config_node(pvn, "tags")) &&
+	if ((cn = dm_config_find_node(pvn, "tags")) &&
 	    !(read_tags(mem, &pv->tags, cn->v))) {
 		log_error("Couldn't read tags for physical volume %s in %s.",
 			  pv_dev_name(pv), vg->name);
@@ -292,13 +292,13 @@
 }
 
 static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
-			 struct logical_volume *lv, const struct config_node *sn,
+			 struct logical_volume *lv, const struct dm_config_node *sn,
 			 struct dm_hash_table *pv_hash)
 {
 	uint32_t area_count = 0u;
 	struct lv_segment *seg;
-	const struct config_node *cn, *sn_child = sn->child;
-	const struct config_value *cv;
+	const struct dm_config_node *cn, *sn_child = sn->child;
+	const struct dm_config_value *cv;
 	uint32_t start_extent, extent_count;
 	struct segment_type *segtype;
 	const char *segtype_str;
@@ -322,7 +322,7 @@
 
 	segtype_str = "striped";
 
-	if ((cn = find_config_node(sn_child, "type"))) {
+	if ((cn = dm_config_find_node(sn_child, "type"))) {
 		cv = cn->v;
 		if (!cv || !cv->v.str) {
 			log_error("Segment type must be a string.");
@@ -350,7 +350,7 @@
 		return_0;
 
 	/* Optional tags */
-	if ((cn = find_config_node(sn_child, "tags")) &&
+	if ((cn = dm_config_find_node(sn_child, "tags")) &&
 	    !(read_tags(mem, &seg->tags, cn->v))) {
 		log_error("Couldn't read tags for a segment of %s/%s.",
 			  vg->name, lv->name);
@@ -377,15 +377,15 @@
 	return 1;
 }
 
-int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
-		      const struct config_node *cn, struct dm_hash_table *pv_hash,
+int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
+		      const struct dm_config_node *cn, struct dm_hash_table *pv_hash,
 		      uint64_t status)
 {
 	unsigned int s;
-	const struct config_value *cv;
+	const struct dm_config_value *cv;
 	struct logical_volume *lv1;
 	struct physical_volume *pv;
-	const char *seg_name = config_parent_name(sn);
+	const char *seg_name = dm_config_parent_name(sn);
 
 	if (!seg->area_count) {
 		log_error("Zero areas not allowed for segment %s", seg_name);
@@ -395,7 +395,7 @@
 	for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
 
 		/* first we read the pv */
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Bad volume name in areas array for segment %s.", seg_name);
 			return 0;
 		}
@@ -405,7 +405,7 @@
 			return 0;
 		}
 
-		if (cv->next->type != CFG_INT) {
+		if (cv->next->type != DM_CFG_INT) {
 			log_error("Bad offset in areas array for segment %s.", seg_name);
 			return 0;
 		}
@@ -442,10 +442,10 @@
 }
 
 static int _read_segments(struct dm_pool *mem, struct volume_group *vg,
-			  struct logical_volume *lv, const struct config_node *lvn,
+			  struct logical_volume *lv, const struct dm_config_node *lvn,
 			  struct dm_hash_table *pv_hash)
 {
-	const struct config_node *sn;
+	const struct dm_config_node *sn;
 	int count = 0, seg_count;
 
 	for (sn = lvn; sn; sn = sn->sib) {
@@ -495,15 +495,15 @@
 
 static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
 			 struct dm_pool *mem,
-			 struct volume_group *vg, const struct config_node *lvn,
-			 const struct config_node *vgn __attribute__((unused)),
+			 struct volume_group *vg, const struct dm_config_node *lvn,
+			 const struct dm_config_node *vgn __attribute__((unused)),
 			 struct dm_hash_table *pv_hash __attribute__((unused)),
 			 struct dm_hash_table *lv_hash,
 			 unsigned *scan_done_once __attribute__((unused)),
 			 unsigned report_missing_devices __attribute__((unused)))
 {
 	struct logical_volume *lv;
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 
 	if (!(lv = alloc_lv(mem)))
 		return_0;
@@ -523,8 +523,8 @@
 	}
 
 	lv->alloc = ALLOC_INHERIT;
-	if ((cn = find_config_node(lvn, "allocation_policy"))) {
-		const struct config_value *cv = cn->v;
+	if ((cn = dm_config_find_node(lvn, "allocation_policy"))) {
+		const struct dm_config_value *cv = cn->v;
 		if (!cv || !cv->v.str) {
 			log_error("allocation_policy must be a string.");
 			return 0;
@@ -554,7 +554,7 @@
 	}
 
 	/* Optional tags */
-	if ((cn = find_config_node(lvn, "tags")) &&
+	if ((cn = dm_config_find_node(lvn, "tags")) &&
 	    !(read_tags(mem, &lv->tags, cn->v))) {
 		log_error("Couldn't read tags for logical volume %s/%s.",
 			  vg->name, lv->name);
@@ -569,8 +569,8 @@
 
 static int _read_lvsegs(struct format_instance *fid __attribute__((unused)),
 			struct dm_pool *mem,
-			struct volume_group *vg, const struct config_node *lvn,
-			const struct config_node *vgn __attribute__((unused)),
+			struct volume_group *vg, const struct dm_config_node *lvn,
+			const struct dm_config_node *vgn __attribute__((unused)),
 			struct dm_hash_table *pv_hash,
 			struct dm_hash_table *lv_hash,
 			unsigned *scan_done_once __attribute__((unused)),
@@ -623,17 +623,17 @@
 static int _read_sections(struct format_instance *fid,
 			  const char *section, section_fn fn,
 			  struct dm_pool *mem,
-			  struct volume_group *vg, const struct config_node *vgn,
+			  struct volume_group *vg, const struct dm_config_node *vgn,
 			  struct dm_hash_table *pv_hash,
 			  struct dm_hash_table *lv_hash,
 			  int optional,
 			  unsigned *scan_done_once)
 {
-	const struct config_node *n;
+	const struct dm_config_node *n;
 	/* Only report missing devices when doing a scan */
 	unsigned report_missing_devices = scan_done_once ? !*scan_done_once : 1;
 
-	if (!(n = find_config_node(vgn, section))) {
+	if (!(n = dm_config_find_node(vgn, section))) {
 		if (!optional) {
 			log_error("Couldn't find section '%s'.", section);
 			return 0;
@@ -652,10 +652,10 @@
 }
 
 static struct volume_group *_read_vg(struct format_instance *fid,
-				     const struct config_tree *cft,
+				     const struct dm_config_tree *cft,
 				     unsigned use_cached_pvs)
 {
-	const struct config_node *vgn, *cn;
+	const struct dm_config_node *vgn, *cn;
 	struct volume_group *vg;
 	struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL;
 	unsigned scan_done_once = use_cached_pvs;
@@ -677,7 +677,7 @@
 
 	vgn = vgn->child;
 
-	if ((cn = find_config_node(vgn, "system_id")) && cn->v) {
+	if ((cn = dm_config_find_node(vgn, "system_id")) && cn->v) {
 		if (!cn->v->v.str) {
 			log_error("system_id must be a string");
 			goto bad;
@@ -725,8 +725,8 @@
 		goto bad;
 	}
 
-	if ((cn = find_config_node(vgn, "allocation_policy"))) {
-		const struct config_value *cv = cn->v;
+	if ((cn = dm_config_find_node(vgn, "allocation_policy"))) {
+		const struct dm_config_value *cv = cn->v;
 		if (!cv || !cv->v.str) {
 			log_error("allocation_policy must be a string.");
 			goto bad;
@@ -760,7 +760,7 @@
 	}
 
 	/* Optional tags */
-	if ((cn = find_config_node(vgn, "tags")) &&
+	if ((cn = dm_config_find_node(vgn, "tags")) &&
 	    !(read_tags(vg->vgmem, &vg->tags, cn->v))) {
 		log_error("Couldn't read tags for volume group %s.", vg->name);
 		goto bad;
@@ -819,33 +819,33 @@
 }
 
 static void _read_desc(struct dm_pool *mem,
-		       const struct config_tree *cft, time_t *when, char **desc)
+		       const struct dm_config_tree *cft, time_t *when, char **desc)
 {
 	const char *d;
 	unsigned int u = 0u;
 	int old_suppress;
 
 	old_suppress = log_suppress(1);
-	d = find_config_str(cft->root, "description", "");
+	d = dm_config_find_str(cft->root, "description", "");
 	log_suppress(old_suppress);
 	*desc = dm_pool_strdup(mem, d);
 
-	(void) get_config_uint32(cft->root, "creation_time", &u);
+	(void) dm_config_get_uint32(cft->root, "creation_time", &u);
 	*when = u;
 }
 
 static const char *_read_vgname(const struct format_type *fmt,
-				const struct config_tree *cft, struct id *vgid,
+				const struct dm_config_tree *cft, struct id *vgid,
 				uint64_t *vgstatus, char **creation_host)
 {
-	const struct config_node *vgn;
+	const struct dm_config_node *vgn;
 	struct dm_pool *mem = fmt->cmd->mem;
 	char *vgname;
 	int old_suppress;
 
 	old_suppress = log_suppress(2);
 	*creation_host = dm_pool_strdup(mem,
-					find_config_str(cft->root,
+					dm_config_find_str(cft->root,
 							"creation_host", ""));
 	log_suppress(old_suppress);
 
diff -ruN -xCVS cvs-clean/lib/format_text/tags.c cvs-daemons-reorg/lib/format_text/tags.c
--- cvs-clean/lib/format_text/tags.c	2010-12-20 14:12:56.000000000 +0100
+++ cvs-daemons-reorg/lib/format_text/tags.c	2011-08-29 19:41:48.000000000 +0200
@@ -61,13 +61,13 @@
 	return_NULL;
 }
 
-int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct config_value *cv)
+int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv)
 {
-	if (cv->type == CFG_EMPTY_ARRAY)
+	if (cv->type == DM_CFG_EMPTY_ARRAY)
 		return 1;
 
 	while (cv) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Found a tag that is not a string");
 			return 0;
 		}
diff -ruN -xCVS cvs-clean/lib/format_text/text_export.h cvs-daemons-reorg/lib/format_text/text_export.h
--- cvs-clean/lib/format_text/text_export.h	2010-01-07 15:45:28.000000000 +0100
+++ cvs-daemons-reorg/lib/format_text/text_export.h	2011-08-29 19:41:48.000000000 +0200
@@ -24,7 +24,7 @@
 
 struct formatter;
 struct lv_segment;
-struct config_node;
+struct dm_config_node;
 
 int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
     __attribute__ ((format(printf, 3, 4)));
@@ -35,7 +35,7 @@
 int out_text(struct formatter *f, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
 
-int out_config_node(struct formatter *f, const struct config_node *cn);
+int out_config_node(struct formatter *f, const struct dm_config_node *cn);
 
 int out_areas(struct formatter *f, const struct lv_segment *seg,
 	      const char *type);
diff -ruN -xCVS cvs-clean/lib/format_text/text_import.h cvs-daemons-reorg/lib/format_text/text_import.h
--- cvs-clean/lib/format_text/text_import.h	2009-12-04 18:48:32.000000000 +0100
+++ cvs-daemons-reorg/lib/format_text/text_import.h	2011-08-29 19:41:48.000000000 +0200
@@ -17,10 +17,10 @@
 #define _LVM_TEXT_IMPORT_H
 
 struct lv_segment;
-struct config_node;
+struct dm_config_node;
 
-int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
-		      const struct config_node *cn, struct dm_hash_table *pv_hash,
+int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
+		      const struct dm_config_node *cn, struct dm_hash_table *pv_hash,
 		      uint64_t status);
 
 #endif
diff -ruN -xCVS cvs-clean/lib/locking/cluster_locking.c cvs-daemons-reorg/lib/locking/cluster_locking.c
--- cvs-clean/lib/locking/cluster_locking.c	2011-08-29 19:54:00.000000000 +0200
+++ cvs-daemons-reorg/lib/locking/cluster_locking.c	2011-08-29 19:41:48.000000000 +0200
@@ -36,7 +36,7 @@
 int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags);
 int query_resource(const char *resource, int *mode);
 void locking_end(void);
-int locking_init(int type, struct config_tree *cf, uint32_t *flags);
+int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags);
 #endif
 
 typedef struct lvm_response {
@@ -606,7 +606,7 @@
 	return 1;
 }
 #else
-int locking_init(int type, struct config_tree *cf, uint32_t *flags)
+int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags)
 {
 	_clvmd_sock = _open_local_sock(0);
 	if (_clvmd_sock == -1)
diff -ruN -xCVS cvs-clean/lib/locking/external_locking.c cvs-daemons-reorg/lib/locking/external_locking.c
--- cvs-clean/lib/locking/external_locking.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/locking/external_locking.c	2011-08-29 19:41:48.000000000 +0200
@@ -26,7 +26,7 @@
 static void (*_end_fn) (void) = NULL;
 static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
 			uint32_t flags) = NULL;
-static int (*_init_fn) (int type, struct config_tree * cft,
+static int (*_init_fn) (int type, struct dm_config_tree * cft,
 			uint32_t *flags) = NULL;
 static int (*_lock_query_fn) (const char *resource, int *mode) = NULL;
 
diff -ruN -xCVS cvs-clean/lib/metadata/lv_manip.c cvs-daemons-reorg/lib/metadata/lv_manip.c
--- cvs-clean/lib/metadata/lv_manip.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/metadata/lv_manip.c	2011-08-29 19:41:48.000000000 +0200
@@ -628,7 +628,7 @@
 	 */
 	unsigned alloc_and_split_meta;
 
-	const struct config_node *cling_tag_list_cn;
+	const struct dm_config_node *cling_tag_list_cn;
 
 	struct dm_list *parallel_areas;	/* PVs to avoid */
 
@@ -1161,7 +1161,7 @@
 	struct pv_area_used *areas;
 	struct pv_area *pva;
 	uint32_t areas_size;
-	const struct config_node *cling_tag_list_cn;
+	const struct dm_config_node *cling_tag_list_cn;
 	int s;	/* Area index of match */
 };
 
@@ -1182,12 +1182,12 @@
  */
 static int _has_matching_pv_tag(struct pv_match *pvmatch, struct pv_segment *pvseg, struct pv_area *pva)
 {
-	const struct config_value *cv;
+	const struct dm_config_value *cv;
 	const char *str;
 	const char *tag_matched;
 
 	for (cv = pvmatch->cling_tag_list_cn->v; cv; cv = cv->next) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Ignoring invalid string in config file entry "
 				  "allocation/cling_tag_list");
 			continue;
@@ -1292,7 +1292,7 @@
  * Is pva on same PV as any existing areas?
  */
 static int _check_cling(struct alloc_handle *ah,
-			const struct config_node *cling_tag_list_cn,
+			const struct dm_config_node *cling_tag_list_cn,
 			struct lv_segment *prev_lvseg, struct pv_area *pva,
 			struct alloc_state *alloc_state)
 {
diff -ruN -xCVS cvs-clean/lib/metadata/metadata.c cvs-daemons-reorg/lib/metadata/metadata.c
--- cvs-clean/lib/metadata/metadata.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/metadata/metadata.c	2011-08-29 19:41:48.000000000 +0200
@@ -687,7 +687,7 @@
 			log_error("Failed to duplicate pv name %s.", pv_names[i]);
 			return 0;
 		}
-		unescape_colons_and_at_signs(pv_name, NULL, NULL);
+		dm_unescape_colons_and_at_signs(pv_name, NULL, NULL);
 		if (!vg_extend_single_pv(vg, pv_name, pp)) {
 			log_error("Unable to add physical volume '%s' to "
 				  "volume group '%s'.", pv_name, vg->name);
diff -ruN -xCVS cvs-clean/lib/metadata/metadata.h cvs-daemons-reorg/lib/metadata/metadata.h
--- cvs-clean/lib/metadata/metadata.h	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/metadata/metadata.h	2011-08-29 19:41:48.000000000 +0200
@@ -98,7 +98,7 @@
 //#define FMT_RESIZE_PV		0x00000080U	/* Supports pvresize? */
 //#define FMT_UNLIMITED_STRIPESIZE 0x00000100U	/* Unlimited stripe size? */
 
-struct config_tree;
+struct dm_config_tree;
 struct metadata_area;
 
 /* Per-format per-metadata area operations */
@@ -455,9 +455,10 @@
  * For internal metadata caching.
  */
 int export_vg_to_buffer(struct volume_group *vg, char **buf);
+int export_vg_to_config_tree(struct volume_group *vg, struct dm_config_tree **cft);
 struct volume_group *import_vg_from_buffer(const char *buf,
 					   struct format_instance *fid);
-struct volume_group *import_vg_from_config_tree(const struct config_tree *cft,
+struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
 						struct format_instance *fid);
 
 /*
diff -ruN -xCVS cvs-clean/lib/metadata/mirror.c cvs-daemons-reorg/lib/metadata/mirror.c
--- cvs-clean/lib/metadata/mirror.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/metadata/mirror.c	2011-08-29 19:41:48.000000000 +0200
@@ -1179,13 +1179,13 @@
 	const char *policy;
 
 	if (log_policy)
-		policy = find_config_str(NULL, "activation/mirror_log_fault_policy",
+		policy = dm_config_find_str(NULL, "activation/mirror_log_fault_policy",
 					 DEFAULT_MIRROR_LOG_FAULT_POLICY);
 	else {
-		policy = find_config_str(NULL, "activation/mirror_image_fault_policy",
+		policy = dm_config_find_str(NULL, "activation/mirror_image_fault_policy",
 					 NULL);
 		if (!policy)
-			policy = find_config_str(NULL, "activation/mirror_device_fault_policy",
+			policy = dm_config_find_str(NULL, "activation/mirror_device_fault_policy",
 						 DEFAULT_MIRROR_IMAGE_FAULT_POLICY);
 	}
 
diff -ruN -xCVS cvs-clean/lib/metadata/segtype.h cvs-daemons-reorg/lib/metadata/segtype.h
--- cvs-clean/lib/metadata/segtype.h	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/metadata/segtype.h	2011-08-29 19:41:48.000000000 +0200
@@ -20,11 +20,11 @@
 
 struct segtype_handler;
 struct cmd_context;
-struct config_tree;
+struct dm_config_tree;
 struct lv_segment;
 struct lv_activate_opts;
 struct formatter;
-struct config_node;
+struct dm_config_node;
 struct dev_manager;
 
 /* Feature flags */
@@ -87,10 +87,10 @@
 	void (*display) (const struct lv_segment * seg);
 	int (*text_export) (const struct lv_segment * seg,
 			    struct formatter * f);
-	int (*text_import_area_count) (const struct config_node * sn,
+	int (*text_import_area_count) (const struct dm_config_node * sn,
 				       uint32_t *area_count);
 	int (*text_import) (struct lv_segment * seg,
-			    const struct config_node * sn,
+			    const struct dm_config_node * sn,
 			    struct dm_hash_table * pv_hash);
 	int (*merge_segments) (struct lv_segment * seg1,
 			       struct lv_segment * seg2);
diff -ruN -xCVS cvs-clean/lib/mirror/mirrored.c cvs-daemons-reorg/lib/mirror/mirrored.c
--- cvs-clean/lib/mirror/mirrored.c	2011-07-11 12:45:20.000000000 +0200
+++ cvs-daemons-reorg/lib/mirror/mirrored.c	2011-08-29 19:41:48.000000000 +0200
@@ -69,46 +69,46 @@
 	log_print(" ");
 }
 
-static int _mirrored_text_import_area_count(const struct config_node *sn, uint32_t *area_count)
+static int _mirrored_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count)
 {
-	if (!get_config_uint32(sn, "mirror_count", area_count)) {
+	if (!dm_config_get_uint32(sn, "mirror_count", area_count)) {
 		log_error("Couldn't read 'mirror_count' for "
-			  "segment '%s'.", config_parent_name(sn));
+			  "segment '%s'.", dm_config_parent_name(sn));
 		return 0;
 	}
 
 	return 1;
 }
 
-static int _mirrored_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _mirrored_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
 			struct dm_hash_table *pv_hash)
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	const char *logname = NULL;
 
-	if (find_config_node(sn, "extents_moved")) {
-		if (get_config_uint32(sn, "extents_moved",
+	if (dm_config_find_node(sn, "extents_moved")) {
+		if (dm_config_get_uint32(sn, "extents_moved",
 				      &seg->extents_copied))
 			seg->status |= PVMOVE;
 		else {
 			log_error("Couldn't read 'extents_moved' for "
 				  "segment %s of logical volume %s.",
-				  config_parent_name(sn), seg->lv->name);
+				  dm_config_parent_name(sn), seg->lv->name);
 			return 0;
 		}
 	}
 
-	if (find_config_node(sn, "region_size")) {
-		if (!get_config_uint32(sn, "region_size",
+	if (dm_config_find_node(sn, "region_size")) {
+		if (!dm_config_get_uint32(sn, "region_size",
 				      &seg->region_size)) {
 			log_error("Couldn't read 'region_size' for "
 				  "segment %s of logical volume %s.",
-				  config_parent_name(sn), seg->lv->name);
+				  dm_config_parent_name(sn), seg->lv->name);
 			return 0;
 		}
 	}
 
-	if ((cn = find_config_node(sn, "mirror_log"))) {
+	if ((cn = dm_config_find_node(sn, "mirror_log"))) {
 		if (!cn->v || !cn->v->v.str) {
 			log_error("Mirror log type must be a string.");
 			return 0;
@@ -117,7 +117,7 @@
 		if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) {
 			log_error("Unrecognised mirror log in "
 				  "segment %s of logical volume %s.",
-				  config_parent_name(sn), seg->lv->name);
+				  dm_config_parent_name(sn), seg->lv->name);
 			return 0;
 		}
 		seg->log_lv->status |= MIRROR_LOG;
@@ -126,14 +126,14 @@
 	if (logname && !seg->region_size) {
 		log_error("Missing region size for mirror log for "
 			  "segment %s of logical volume %s.",
-			  config_parent_name(sn), seg->lv->name);
+			  dm_config_parent_name(sn), seg->lv->name);
 		return 0;
 	}
 
-	if (!(cn = find_config_node(sn, "mirrors"))) {
+	if (!(cn = dm_config_find_node(sn, "mirrors"))) {
 		log_error("Couldn't find mirrors array for "
 			  "segment %s of logical volume %s.",
-			  config_parent_name(sn), seg->lv->name);
+			  dm_config_parent_name(sn), seg->lv->name);
 		return 0;
 	}
 
diff -ruN -xCVS cvs-clean/lib/misc/lvm-string.c cvs-daemons-reorg/lib/misc/lvm-string.c
--- cvs-clean/lib/misc/lvm-string.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/misc/lvm-string.c	2011-08-29 19:41:48.000000000 +0200
@@ -44,248 +44,6 @@
 }
 
 /*
- * Count occurences of 'c' in 'str' until we reach a null char.
- *
- * Returns:
- *  len - incremented for each char we encounter.
- *  count - number of occurrences of 'c' and 'c2'.
- */
-static void _count_chars(const char *str, size_t *len, int *count,
-			 const int c1, const int c2)
-{
-	const char *ptr;
-
-	for (ptr = str; *ptr; ptr++, (*len)++)
-		if (*ptr == c1 || *ptr == c2)
-			(*count)++;
-}
-
-/*
- * Count occurences of 'c' in 'str' of length 'size'.
- *
- * Returns:
- *   Number of occurrences of 'c'
- */
-unsigned count_chars(const char *str, size_t len, const int c)
-{
-	size_t i;
-	unsigned count = 0;
-
-	for (i = 0; i < len; i++)
-		if (str[i] == c)
-			count++;
-
-	return count;
-}
-
-/*
- * Length of string after escaping double quotes and backslashes.
- */
-size_t escaped_len(const char *str)
-{
-	size_t len = 1;
-	int count = 0;
-
-	_count_chars(str, &len, &count, '\"', '\\');
-
-	return count + len;
-}
-
-/*
- * Copies a string, quoting orig_char with quote_char.
- * Optionally also quote quote_char.
- */
-static void _quote_characters(char **out, const char *src,
-			      const int orig_char, const int quote_char,
-			      int quote_quote_char)
-{
-	while (*src) {
-		if (*src == orig_char ||
-		    (*src == quote_char && quote_quote_char))
-			*(*out)++ = quote_char;
-
-		*(*out)++ = *src++;
-	}
-}
-
-static void _unquote_one_character(char *src, const char orig_char,
-				   const char quote_char)
-{
-	char *out;
-	char s, n;
-
-	/* Optimise for the common case where no changes are needed. */
-	while ((s = *src++)) {
-		if (s == quote_char &&
-		    ((n = *src) == orig_char || n == quote_char)) {
-			out = src++;
-			*(out - 1) = n;
-
-			while ((s = *src++)) {
-				if (s == quote_char &&
-				    ((n = *src) == orig_char || n == quote_char)) {
-					s = n;
-					src++;
-				}
-				*out = s;
-				out++;
-			}
-
-			*out = '\0';
-			return;
-		}
-	}
-}
-
-/*
- * Unquote each character given in orig_char array and unquote quote_char
- * as well. Also save the first occurrence of each character from orig_char
- * that was found unquoted in arr_substr_first_unquoted array. This way we can
- * process several characters in one go.
- */
-static void _unquote_characters(char *src, const char *orig_chars,
-				size_t num_orig_chars,
-				const char quote_char,
-				char *arr_substr_first_unquoted[])
-{
-	char *out = src;
-	char c, s, n;
-	unsigned i;
-
-	while ((s = *src++)) {
-		for (i = 0; i < num_orig_chars; i++) {
-			c = orig_chars[i];
-			if (s == quote_char &&
-			    ((n = *src) == c || n == quote_char)) {
-				s = n;
-				src++;
-				break;
-			}
-			if (arr_substr_first_unquoted && (s == c) &&
-			    !arr_substr_first_unquoted[i])
-				arr_substr_first_unquoted[i] = out;
-		};
-		*out++ = s;
-	}
-
-	*out = '\0';
-}
-
-/*
- * Copies a string, quoting hyphens with hyphens.
- */
-static void _quote_hyphens(char **out, const char *src)
-{
-	_quote_characters(out, src, '-', '-', 0);
-}
-
-/*
- * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
- */
-char *build_dm_name(struct dm_pool *mem, const char *vgname,
-		    const char *lvname, const char *layer)
-{
-	size_t len = 1;
-	int hyphens = 1;
-	char *r, *out;
-
-	_count_chars(vgname, &len, &hyphens, '-', 0);
-	_count_chars(lvname, &len, &hyphens, '-', 0);
-
-	if (layer && *layer) {
-		_count_chars(layer, &len, &hyphens, '-', 0);
-		hyphens++;
-	}
-
-	len += hyphens;
-
-	if (!(r = dm_pool_alloc(mem, len))) {
-		log_error("build_dm_name: Allocation failed for %" PRIsize_t
-			  " for %s %s %s.", len, vgname, lvname, layer);
-		return NULL;
-	}
-
-	out = r;
-	_quote_hyphens(&out, vgname);
-	*out++ = '-';
-	_quote_hyphens(&out, lvname);
-
-	if (layer && *layer) {
-		/* No hyphen if the layer begins with _ e.g. _mlog */
-		if (*layer != '_')
-			*out++ = '-';
-		_quote_hyphens(&out, layer);
-	}
-	*out = '\0';
-
-	return r;
-}
-
-char *build_dm_uuid(struct dm_pool *mem, const char *lvid, const char *layer)
-{
-	char *dmuuid;
-	size_t len;
-
-	if (!layer)
-		layer = "";
-
-	len = sizeof(UUID_PREFIX) + strlen(lvid) + strlen(layer) + 1;
-
-	if (!(dmuuid = dm_pool_alloc(mem, len))) {
-		log_error("build_dm_name: Allocation failed for %" PRIsize_t
-			  " %s %s.", len, lvid, layer);
-		return NULL;
-	}
-
-	sprintf(dmuuid, UUID_PREFIX "%s%s%s", lvid, (*layer) ? "-" : "", layer);
-
-	return dmuuid;
-}
-
-/*
- * Copies a string, quoting double quotes with backslashes.
- */
-char *escape_double_quotes(char *out, const char *src)
-{
-	char *buf = out;
-
-	_quote_characters(&buf, src, '\"', '\\', 1);
-	*buf = '\0';
-
-	return out;
-}
-
-/*
- * Undo quoting in situ.
- */
-void unescape_double_quotes(char *src)
-{
-	_unquote_one_character(src, '\"', '\\');
-}
-
-/*
- * Unescape colons and "at" signs in situ and save the substrings
- * starting at the position of the first unescaped colon and the
- * first unescaped "at" sign. This is normally used to unescape
- * device names used as PVs.
- */
-void unescape_colons_and_at_signs(char *src,
-				  char **substr_first_unquoted_colon,
-				  char **substr_first_unquoted_at_sign)
-{
-	const char *orig_chars = ":@";
-	char *arr_substr_first_unquoted[] = {NULL, NULL, NULL};
-
-	_unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted);
-
-	if (substr_first_unquoted_colon)
-		*substr_first_unquoted_colon = arr_substr_first_unquoted[0];
-
-	if (substr_first_unquoted_at_sign)
-		*substr_first_unquoted_at_sign = arr_substr_first_unquoted[1];
-}
-
-/*
  * A-Za-z0-9._-+/=!:&#
  */
 int validate_tag(const char *n)
@@ -392,3 +150,9 @@
 
 	return rc;
 }
+
+char *build_dm_uuid(struct dm_pool *mem, const char *lvid,
+		    const char *layer)
+{
+	return dm_build_dm_uuid(mem, UUID_PREFIX, lvid, layer);
+}
diff -ruN -xCVS cvs-clean/lib/misc/lvm-string.h cvs-daemons-reorg/lib/misc/lvm-string.h
--- cvs-clean/lib/misc/lvm-string.h	2010-11-17 11:19:30.000000000 +0100
+++ cvs-daemons-reorg/lib/misc/lvm-string.h	2011-08-29 19:41:48.000000000 +0200
@@ -27,8 +27,6 @@
 int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
   __attribute__ ((format(printf, 3, 4)));
 
-char *build_dm_name(struct dm_pool *mem, const char *vg,
-                    const char *lv, const char *layer);
 char *build_dm_uuid(struct dm_pool *mem, const char *lvid,
 		    const char *layer);
 
@@ -38,36 +36,4 @@
 int apply_lvname_restrictions(const char *name);
 int is_reserved_lvname(const char *name);
 
-/*
- * Returns number of occurrences of c in first len characters of str.
- */
-unsigned count_chars(const char *str, size_t len, const int c);
-
-/*
- * Returns what length of escaped string would be including terminating NUL.
- */
-size_t escaped_len(const char *str);
-
-/*
- * Copies a string from src to out. 
- * Double quotation marks and backslashes are quoted with a backslash.
- * Caller must ensure *out has enough space - see escaped_len().
- * Returns *out.
- */
-char *escape_double_quotes(char *out, const char *src);
-
-/*
- * Removes quoting of double quotation marks and backslashes in situ.
- */
-void unescape_double_quotes(char *src);
-
-/*
- * Unescape colons and at signs in situ and save the substring starting
- * at the position of the first unescaped colon and the first unescaped
- * "at" sign.
- */
-void unescape_colons_and_at_signs(char *src,
-				  char **substr_first_unquoted_colon,
-				  char **substr_first_unquoted_at_sign);
-
 #endif
diff -ruN -xCVS cvs-clean/lib/mm/memlock.c cvs-daemons-reorg/lib/mm/memlock.c
--- cvs-clean/lib/mm/memlock.c	2011-06-15 14:30:22.000000000 +0200
+++ cvs-daemons-reorg/lib/mm/memlock.c	2011-08-29 19:41:48.000000000 +0200
@@ -146,10 +146,10 @@
  * mlock/munlock memory areas from /proc/self/maps
  * format described in kernel/Documentation/filesystem/proc.txt
  */
-static int _maps_line(const struct config_node *cn, lvmlock_t lock,
+static int _maps_line(const struct dm_config_node *cn, lvmlock_t lock,
 		      const char* line, size_t* mstats)
 {
-	const struct config_value *cv;
+	const struct dm_config_value *cv;
 	long from, to;
 	int pos;
 	unsigned i;
@@ -188,7 +188,7 @@
 			}
 	} else {
 		for (cv = cn->v; cv; cv = cv->next) {
-			if ((cv->type != CFG_STRING) || !cv->v.str[0])
+			if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
 				continue;
 			if (strstr(line + pos, cv->v.str)) {
 				log_debug("mlock_filter '%s' matches '%s': Skipping.",
@@ -228,7 +228,7 @@
 
 static int _memlock_maps(struct cmd_context *cmd, lvmlock_t lock, size_t *mstats)
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	char *line, *line_end;
 	size_t len;
 	ssize_t n;
diff -ruN -xCVS cvs-clean/lib/raid/raid.c cvs-daemons-reorg/lib/raid/raid.c
--- cvs-clean/lib/raid/raid.c	2011-08-24 15:41:47.000000000 +0200
+++ cvs-daemons-reorg/lib/raid/raid.c	2011-08-29 19:41:48.000000000 +0200
@@ -32,25 +32,25 @@
 	return seg->segtype->name;
 }
 
-static int _raid_text_import_area_count(const struct config_node *sn,
+static int _raid_text_import_area_count(const struct dm_config_node *sn,
 					uint32_t *area_count)
 {
-	if (!get_config_uint32(sn, "device_count", area_count)) {
+	if (!dm_config_get_uint32(sn, "device_count", area_count)) {
 		log_error("Couldn't read 'device_count' for "
-			  "segment '%s'.", config_parent_name(sn));
+			  "segment '%s'.", dm_config_parent_name(sn));
 		return 0;
 	}
 	return 1;
 }
 
 static int _raid_text_import_areas(struct lv_segment *seg,
-				   const struct config_node *sn,
-				   const struct config_node *cn)
+				   const struct dm_config_node *sn,
+				   const struct dm_config_node *cn)
 {
 	unsigned int s;
-	const struct config_value *cv;
+	const struct dm_config_value *cv;
 	struct logical_volume *lv1;
-	const char *seg_name = config_parent_name(sn);
+	const char *seg_name = dm_config_parent_name(sn);
 
 	if (!seg->area_count) {
 		log_error("No areas found for segment %s", seg_name);
@@ -58,7 +58,7 @@
 	}
 
 	for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
-		if (cv->type != CFG_STRING) {
+		if (cv->type != DM_CFG_STRING) {
 			log_error("Bad volume name in areas array for segment %s.", seg_name);
 			return 0;
 		}
@@ -101,31 +101,31 @@
 }
 
 static int _raid_text_import(struct lv_segment *seg,
-			     const struct config_node *sn,
+			     const struct dm_config_node *sn,
 			     struct dm_hash_table *pv_hash)
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 
-	if (find_config_node(sn, "region_size")) {
-		if (!get_config_uint32(sn, "region_size", &seg->region_size)) {
+	if (dm_config_find_node(sn, "region_size")) {
+		if (!dm_config_get_uint32(sn, "region_size", &seg->region_size)) {
 			log_error("Couldn't read 'region_size' for "
 				  "segment %s of logical volume %s.",
-				  config_parent_name(sn), seg->lv->name);
+				  dm_config_parent_name(sn), seg->lv->name);
 			return 0;
 		}
 	}
-	if (find_config_node(sn, "stripe_size")) {
-		if (!get_config_uint32(sn, "stripe_size", &seg->stripe_size)) {
+	if (dm_config_find_node(sn, "stripe_size")) {
+		if (!dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) {
 			log_error("Couldn't read 'stripe_size' for "
 				  "segment %s of logical volume %s.",
-				  config_parent_name(sn), seg->lv->name);
+				  dm_config_parent_name(sn), seg->lv->name);
 			return 0;
 		}
 	}
-	if (!(cn = find_config_node(sn, "raids"))) {
+	if (!(cn = dm_config_find_node(sn, "raids"))) {
 		log_error("Couldn't find RAID array for "
 			  "segment %s of logical volume %s.",
-			  config_parent_name(sn), seg->lv->name);
+			  dm_config_parent_name(sn), seg->lv->name);
 		return 0;
 	}
 
diff -ruN -xCVS cvs-clean/lib/replicator/replicator.c cvs-daemons-reorg/lib/replicator/replicator.c
--- cvs-clean/lib/replicator/replicator.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/replicator/replicator.c	2011-08-29 19:41:48.000000000 +0200
@@ -36,7 +36,7 @@
  */
 #define SEG_LOG_ERROR(t, p...) \
 	log_error(t " segment %s of logical volume %s.", ## p, \
-		  config_parent_name(sn), seg->lv->name), 0;
+		  dm_config_parent_name(sn), seg->lv->name), 0;
 
 
 /*
@@ -58,24 +58,24 @@
 		log_print("  Replicator volume\t%s", seg->rlog_lv->name);
 }
 
-/* Wrapper for get_config_uint32() with default value */
-static uint32_t _get_config_uint32(const struct config_node *cn,
+/* Wrapper for dm_config_get_uint32() with default value */
+static uint32_t _get_config_uint32(const struct dm_config_node *cn,
 				   const char *path,
 				   uint32_t def)
 {
 	uint32_t t;
 
-	return get_config_uint32(cn, path, &t) ? t : def;
+	return dm_config_get_uint32(cn, path, &t) ? t : def;
 }
 
-/* Wrapper for get_config_uint64() with default value */
-static uint64_t _get_config_uint64(const struct config_node *cn,
+/* Wrapper for dm_config_get_uint64() with default value */
+static uint64_t _get_config_uint64(const struct dm_config_node *cn,
 				   const char *path,
 				   uint64_t def)
 {
 	uint64_t t;
 
-	return get_config_uint64(cn, path, &t) ? t : def;
+	return dm_config_get_uint64(cn, path, &t) ? t : def;
 }
 
 
@@ -86,13 +86,13 @@
 };
 
 /* Parse state string */
-static replicator_state_t _get_state(const struct config_node *sn,
+static replicator_state_t _get_state(const struct dm_config_node *sn,
 				     const char *path, replicator_state_t def)
 {
 	const char *str;
 	unsigned i;
 
-	if (get_config_str(sn, path, &str)) {
+	if (dm_config_get_str(sn, path, &str)) {
 		for (i = 0; i < sizeof(_state_txt)/sizeof(_state_txt[0]); ++i)
 			if (strcasecmp(str, _state_txt[i]) == 0)
 				return (replicator_state_t) i;
@@ -115,13 +115,13 @@
 
 
 /* Parse action string */
-static dm_replicator_mode_t _get_op_mode(const struct config_node *sn,
+static dm_replicator_mode_t _get_op_mode(const struct dm_config_node *sn,
 					 const char *path, dm_replicator_mode_t def)
 {
 	const char *str;
 	unsigned i;
 
-	if (get_config_str(sn, path, &str)) {
+	if (dm_config_get_str(sn, path, &str)) {
 		for (i = 0; i < sizeof(_op_mode_txt)/sizeof(_op_mode_txt[0]); ++i)
 			if (strcasecmp(str, _op_mode_txt[i]) == 0) {
 				log_very_verbose("Setting %s to %s",
@@ -162,16 +162,16 @@
 /* Parse replicator site element */
 static int _add_site(struct lv_segment *seg,
 		     const char *key,
-		     const struct config_node *sn)
+		     const struct dm_config_node *sn)
 {
 	struct dm_pool *mem = seg->lv->vg->vgmem;
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	struct replicator_site *rsite;
 
 	if (!(rsite = _get_site(seg->lv, key)))
 		return_0;
 
-	if (!find_config_node(sn, "site_index"))
+	if (!dm_config_find_node(sn, "site_index"))
 		return SEG_LOG_ERROR("Mandatory site_index is missing for");
 
 	rsite->state = _get_state(sn, "state", REPLICATOR_STATE_PASSIVE);
@@ -204,8 +204,8 @@
 					      rsite->op_mode);
 	}
 
-	if ((cn = find_config_node(sn, "volume_group"))) {
-		if (!cn->v || cn->v->type != CFG_STRING)
+	if ((cn = dm_config_find_node(sn, "volume_group"))) {
+		if (!cn->v || cn->v->type != DM_CFG_STRING)
 			return SEG_LOG_ERROR("volume_group must be a string in");
 
 		if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str)))
@@ -220,25 +220,25 @@
 
 /* Import replicator segment */
 static int _replicator_text_import(struct lv_segment *seg,
-				   const struct config_node *sn,
+				   const struct dm_config_node *sn,
 				   struct dm_hash_table *pv_hash __attribute__((unused)))
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	struct logical_volume *rlog_lv;
 
 	if (!replicator_add_replicator_dev(seg->lv, NULL))
 		return_0;
 
-	if (!(cn = find_config_node(sn, "replicator_log")) ||
-	    !cn->v || cn->v->type != CFG_STRING)
+	if (!(cn = dm_config_find_node(sn, "replicator_log")) ||
+	    !cn->v || cn->v->type != DM_CFG_STRING)
 		return SEG_LOG_ERROR("Replicator log type must be a string in");
 
 	if (!(rlog_lv = find_lv(seg->lv->vg, cn->v->v.str)))
 		return SEG_LOG_ERROR("Unknown replicator log %s in",
 				     cn->v->v.str);
 
-	if (!(cn = find_config_node(sn, "replicator_log_type")) ||
-	    !cn->v || cn->v->type != CFG_STRING)
+	if (!(cn = dm_config_find_node(sn, "replicator_log_type")) ||
+	    !cn->v || cn->v->type != DM_CFG_STRING)
 		return SEG_LOG_ERROR("Replicator log's type must be a string in");
 	if (strcasecmp(cn->v->v.str, "ringbuffer"))
 		return SEG_LOG_ERROR("Only ringbuffer replicator log type is supported in");
@@ -443,7 +443,7 @@
 
 static int _add_device(struct lv_segment *seg,
 		       const char *site_name,
-		       const struct config_node *sn,
+		       const struct dm_config_node *sn,
 		       uint64_t devidx)
 {
 	struct dm_pool *mem = seg->lv->vg->vgmem;
@@ -453,19 +453,19 @@
 	struct replicator_device *rdev;
 	const char *dev_str = NULL;
 	const char *slog_str = NULL;
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 
 	dm_list_iterate_items(rdev, &rsite->rdevices)
 		if (rdev->replicator_dev == seg)
 			return SEG_LOG_ERROR("Duplicate site found in");
 
-	if ((cn = find_config_node(sn, "sync_log"))) {
+	if ((cn = dm_config_find_node(sn, "sync_log"))) {
 		if (!cn->v || !cn->v->v.str)
 			return SEG_LOG_ERROR("Sync log must be a string in");
 		slog_str = cn->v->v.str;
 	}
 
-	if (!(cn = find_config_node(sn, "logical_volume")) ||
+	if (!(cn = dm_config_find_node(sn, "logical_volume")) ||
 	    !cn->v || !cn->v->v.str)
 		return SEG_LOG_ERROR("Logical volume must be a string in");
 
@@ -520,14 +520,14 @@
 
 /* Import replicator segment */
 static int _replicator_dev_text_import(struct lv_segment *seg,
-				       const struct config_node *sn,
+				       const struct dm_config_node *sn,
 				       struct dm_hash_table *pv_hash __attribute__((unused)))
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 	struct logical_volume *replicator;
 	uint64_t devidx;
 
-	if (!(cn = find_config_node(sn, "replicator")))
+	if (!(cn = dm_config_find_node(sn, "replicator")))
 		return SEG_LOG_ERROR("Replicator is missing for");
 
 	if (!cn->v || !cn->v->v.str)
@@ -542,8 +542,8 @@
 	log_very_verbose("replicator=%s", replicator->name);
 
 	/* Mandatory */
-	if (!find_config_node(sn, "device_index") ||
-	    !get_config_uint64(sn, "device_index", &devidx))
+	if (!dm_config_find_node(sn, "device_index") ||
+	    !dm_config_get_uint64(sn, "device_index", &devidx))
 		return SEG_LOG_ERROR("Could not read 'device_index' for");
 
 	/* Read devices from sites */
diff -ruN -xCVS cvs-clean/lib/snapshot/snapshot.c cvs-daemons-reorg/lib/snapshot/snapshot.c
--- cvs-clean/lib/snapshot/snapshot.c	2011-07-11 12:45:20.000000000 +0200
+++ cvs-daemons-reorg/lib/snapshot/snapshot.c	2011-08-29 19:41:48.000000000 +0200
@@ -37,7 +37,7 @@
 	return _snap_name(seg);
 }
 
-static int _snap_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _snap_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
 			struct dm_hash_table *pv_hash __attribute__((unused)))
 {
 	uint32_t chunk_size;
@@ -45,28 +45,28 @@
 	struct logical_volume *org, *cow;
 	int old_suppress, merge = 0;
 
-	if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
+	if (!dm_config_get_uint32(sn, "chunk_size", &chunk_size)) {
 		log_error("Couldn't read chunk size for snapshot.");
 		return 0;
 	}
 
 	old_suppress = log_suppress(1);
 
-	if ((cow_name = find_config_str(sn, "merging_store", NULL))) {
-		if (find_config_str(sn, "cow_store", NULL)) {
+	if ((cow_name = dm_config_find_str(sn, "merging_store", NULL))) {
+		if (dm_config_find_str(sn, "cow_store", NULL)) {
 			log_suppress(old_suppress);
 			log_error("Both snapshot cow and merging storage were specified.");
 			return 0;
 		}
 		merge = 1;
 	}
-	else if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
+	else if (!(cow_name = dm_config_find_str(sn, "cow_store", NULL))) {
 		log_suppress(old_suppress);
 		log_error("Snapshot cow storage not specified.");
 		return 0;
 	}
 
-	if (!(org_name = find_config_str(sn, "origin", NULL))) {
+	if (!(org_name = dm_config_find_str(sn, "origin", NULL))) {
 		log_suppress(old_suppress);
 		log_error("Snapshot origin not specified.");
 		return 0;
diff -ruN -xCVS cvs-clean/lib/striped/striped.c cvs-daemons-reorg/lib/striped/striped.c
--- cvs-clean/lib/striped/striped.c	2011-07-11 12:45:20.000000000 +0200
+++ cvs-daemons-reorg/lib/striped/striped.c	2011-08-29 19:41:48.000000000 +0200
@@ -57,32 +57,32 @@
 	log_print(" ");
 }
 
-static int _striped_text_import_area_count(const struct config_node *sn, uint32_t *area_count)
+static int _striped_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count)
 {
-	if (!get_config_uint32(sn, "stripe_count", area_count)) {
+	if (!dm_config_get_uint32(sn, "stripe_count", area_count)) {
 		log_error("Couldn't read 'stripe_count' for "
-			  "segment '%s'.", config_parent_name(sn));
+			  "segment '%s'.", dm_config_parent_name(sn));
 		return 0;
 	}
 
 	return 1;
 }
 
-static int _striped_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _striped_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
 			struct dm_hash_table *pv_hash)
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 
 	if ((seg->area_count != 1) &&
-	    !get_config_uint32(sn, "stripe_size", &seg->stripe_size)) {
+	    !dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) {
 		log_error("Couldn't read stripe_size for segment %s "
-			  "of logical volume %s.", config_parent_name(sn), seg->lv->name);
+			  "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name);
 		return 0;
 	}
 
-	if (!(cn = find_config_node(sn, "stripes"))) {
+	if (!(cn = dm_config_find_node(sn, "stripes"))) {
 		log_error("Couldn't find stripes array for segment %s "
-			  "of logical volume %s.", config_parent_name(sn), seg->lv->name);
+			  "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name);
 		return 0;
 	}
 
diff -ruN -xCVS cvs-clean/lib/thin/thin.c cvs-daemons-reorg/lib/thin/thin.c
--- cvs-clean/lib/thin/thin.c	2011-08-26 20:15:14.000000000 +0200
+++ cvs-daemons-reorg/lib/thin/thin.c	2011-08-29 19:41:48.000000000 +0200
@@ -36,39 +36,39 @@
  */
 #define SEG_LOG_ERROR(t, p...) \
 	log_error(t " segment %s of logical volume %s.", ## p, \
-		  config_parent_name(sn), seg->lv->name), 0;
+		  dm_config_parent_name(sn), seg->lv->name), 0;
 
 static const char *_thin_pool_name(const struct lv_segment *seg)
 {
 	return seg->segtype->name;
 }
 
-static int _thin_pool_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _thin_pool_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
 			struct dm_hash_table *pv_hash __attribute__((unused)))
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 
-	if (!(cn = find_config_node(sn, "data")) ||
-	    !cn->v || cn->v->type != CFG_STRING)
+	if (!(cn = dm_config_find_node(sn, "data")) ||
+	    !cn->v || cn->v->type != DM_CFG_STRING)
 		return SEG_LOG_ERROR("Thin pool data must be a string in");
 
 	if (!(seg->data_lv = find_lv(seg->lv->vg, cn->v->v.str)))
 		return SEG_LOG_ERROR("Unknown pool data %s in",
 				     cn->v->v.str);
 
-	if (!(cn = find_config_node(sn, "metadata")) ||
-	    !cn->v || cn->v->type != CFG_STRING)
+	if (!(cn = dm_config_find_node(sn, "metadata")) ||
+	    !cn->v || cn->v->type != DM_CFG_STRING)
 		return SEG_LOG_ERROR("Thin pool metadata must be a string in");
 
 	if (!(seg->metadata_lv = find_lv(seg->lv->vg, cn->v->v.str)))
 		return SEG_LOG_ERROR("Unknown pool metadata %s in",
 				     cn->v->v.str);
 
-	if (!get_config_uint64(sn, "transaction_id", &seg->transaction_id))
+	if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id))
 		return SEG_LOG_ERROR("Could not read transaction_id for");
 
-	if (find_config_node(sn, "zero_new_blocks") &&
-	    !get_config_uint32(sn, "zero_new_blocks", &seg->zero_new_blocks))
+	if (dm_config_find_node(sn, "zero_new_blocks") &&
+	    !dm_config_get_uint32(sn, "zero_new_blocks", &seg->zero_new_blocks))
 		return SEG_LOG_ERROR("Could not read zero_new_blocks for");
 
 	return 1;
@@ -90,21 +90,21 @@
 	return seg->segtype->name;
 }
 
-static int _thin_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _thin_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
 			struct dm_hash_table *pv_hash __attribute__((unused)))
 {
-	const struct config_node *cn;
+	const struct dm_config_node *cn;
 
-	if (!(cn = find_config_node(sn, "thin_pool")) ||
-	    !cn->v || cn->v->type != CFG_STRING)
+	if (!(cn = dm_config_find_node(sn, "thin_pool")) ||
+	    !cn->v || cn->v->type != DM_CFG_STRING)
 		return SEG_LOG_ERROR("Thin pool must be a string in");
 
 	if (!(seg->thin_pool_lv = find_lv(seg->lv->vg, cn->v->v.str)))
 		return SEG_LOG_ERROR("Unknown thin pool %s in",
 				     cn->v->v.str);
 
-	if ((cn = find_config_node(sn, "origin"))) {
-                if (!cn->v || cn->v->type != CFG_STRING)
+	if ((cn = dm_config_find_node(sn, "origin"))) {
+                if (!cn->v || cn->v->type != DM_CFG_STRING)
 			return SEG_LOG_ERROR("Thin pool origin must be a string in");
 
 		if (!(seg->origin = find_lv(seg->lv->vg, cn->v->v.str)))
@@ -112,7 +112,7 @@
 					     cn->v->v.str);
 	}
 
-	if (!get_config_uint64(sn, "device_id", &seg->device_id))
+	if (!dm_config_get_uint64(sn, "device_id", &seg->device_id))
 		return SEG_LOG_ERROR("Could not read device_id for");
 
 	return 1;
diff -ruN -xCVS cvs-clean/lib/unknown/unknown.c cvs-daemons-reorg/lib/unknown/unknown.c
--- cvs-clean/lib/unknown/unknown.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/lib/unknown/unknown.c	2011-08-29 19:41:48.000000000 +0200
@@ -32,17 +32,17 @@
 	return seg->segtype->name;
 }
 
-static int _unknown_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _unknown_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
 				struct dm_hash_table *pv_hash)
 {
-	struct config_node *new, *last = NULL, *head = NULL;
-	const struct config_node *current;
+	struct dm_config_node *new, *last = NULL, *head = NULL;
+	const struct dm_config_node *current;
 	log_verbose("importing unknown segment");
 	for (current = sn; current != NULL; current = current->sib) {
 		if (!strcmp(current->key, "type") || !strcmp(current->key, "start_extent") ||
 		    !strcmp(current->key, "tags") || !strcmp(current->key, "extent_count"))
 			continue;
-		new = clone_config_node_with_mem(seg->lv->vg->vgmem, current, 0);
+		new = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, current, 0);
 		if (!new)
 			return_0;
 		if (last)
@@ -57,7 +57,7 @@
 
 static int _unknown_text_export(const struct lv_segment *seg, struct formatter *f)
 {
-	struct config_node *cn = seg->segtype_private;
+	struct dm_config_node *cn = seg->segtype_private;
 	return out_config_node(f, cn);
 }
 
diff -ruN -xCVS cvs-clean/libdm/libdevmapper.h cvs-daemons-reorg/libdm/libdevmapper.h
--- cvs-clean/libdm/libdevmapper.h	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/libdm/libdevmapper.h	2011-08-29 19:46:00.000000000 +0200
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <stdarg.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 
 #ifdef linux
 #  include <linux/types.h>
@@ -1014,6 +1015,46 @@
  */
 const char *dm_basename(const char *path);
 
+/*
+ * Count occurences of 'c' in 'str' of length 'size'.
+ *
+ * Returns:
+ *   Number of occurrences of 'c'
+ */
+unsigned dm_count_chars(const char *str, size_t len, const int c);
+
+/*
+ * Length of string after escaping double quotes and backslashes.
+ */
+size_t dm_escaped_len(const char *str);
+
+/*
+ * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
+ */
+char *dm_build_dm_name(struct dm_pool *mem, const char *vgname,
+		       const char *lvname, const char *layer);
+char *dm_build_dm_uuid(struct dm_pool *mem, const char *prefix, const char *lvid, const char *layer);
+
+/*
+ * Copies a string, quoting double quotes with backslashes.
+ */
+char *dm_escape_double_quotes(char *out, const char *src);
+
+/*
+ * Undo quoting in situ.
+ */
+void dm_unescape_double_quotes(char *src);
+
+/*
+ * Unescape colons and "at" signs in situ and save the substrings
+ * starting at the position of the first unescaped colon and the
+ * first unescaped "at" sign. This is normally used to unescape
+ * device names used as PVs.
+ */
+void dm_unescape_colons_and_at_signs(char *src,
+				     char **substr_first_unquoted_colon,
+				     char **substr_first_unquoted_at_sign);
+
 /**************************
  * file/stream manipulation
  **************************/
@@ -1181,6 +1222,108 @@
 void dm_report_field_set_value(struct dm_report_field *field, const void *value,
 			       const void *sortvalue);
 
+
+/*********************************
+ * config file parse/prettyprint
+ *********************************/
+enum {
+	DM_CFG_STRING,
+	DM_CFG_FLOAT,
+	DM_CFG_INT,
+	DM_CFG_EMPTY_ARRAY
+};
+
+struct dm_config_value {
+	int type;
+	union {
+		int64_t i;
+		float r;
+		const char *str;
+	} v;
+	struct dm_config_value *next;	/* for arrays */
+};
+
+struct dm_config_node {
+	const char *key;
+	struct dm_config_node *parent, *sib, *child;
+	struct dm_config_value *v;
+};
+
+struct dm_config_tree {
+	struct dm_config_node *root;
+	struct dm_config_tree *cascade;
+};
+
+struct dm_config_tree *dm_config_create(const char *filename, int keep_open);
+struct dm_config_tree *dm_config_from_string(const char *config_settings);
+int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end);
+
+void *dm_config_get_custom(struct dm_config_tree *cft);
+int dm_config_check_file(struct dm_config_tree *cft, const char **filename, struct stat *info);
+int dm_config_keep_open(struct dm_config_tree *ctf);
+
+void dm_config_set_custom(struct dm_config_tree *cft, void *custom);
+
+void dm_config_destroy(struct dm_config_tree *cft);
+
+int dm_config_write(struct dm_config_tree *cft, const char *file,
+		    int argc, char **argv);
+
+typedef int (*dm_putline_fn)(const char *line, void *baton);
+int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton);
+
+time_t dm_config_timestamp(struct dm_config_tree *cft);
+int dm_config_changed(struct dm_config_tree *cft);
+
+const struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path);
+const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail);
+int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail);
+float dm_config_find_float(const struct dm_config_node *cn, const char *path, float fail);
+
+const struct dm_config_node *dm_config_tree_find_node(
+	const struct dm_config_tree *cft, const char *path);
+const char *dm_config_tree_find_str(const struct dm_config_tree *cft,
+				    const char *path, const char *fail);
+int dm_config_tree_find_int(const struct dm_config_tree *cft,
+			    const char *path, int fail);
+int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft,
+				  const char *path, int64_t fail);
+float dm_config_tree_find_float(const struct dm_config_tree *cft,
+				const char *path, float fail);
+int dm_config_tree_find_bool(const struct dm_config_tree *cft,
+			     const char *path, int fail);
+
+/*
+ * Understands (0, ~0), (y, n), (yes, no), (on,
+ * off), (true, false).
+ */
+int dm_config_find_bool(const struct dm_config_node *cn, const char *path, int fail);
+
+int dm_config_get_uint32(const struct dm_config_node *cn, const char *path,
+			 uint32_t *result);
+
+int dm_config_get_uint64(const struct dm_config_node *cn, const char *path,
+			 uint64_t *result);
+
+int dm_config_get_str(const struct dm_config_node *cn, const char *path,
+		      const char **result);
+
+unsigned dm_config_maybe_section(const char *str, unsigned len);
+
+const char *dm_config_parent_name(const struct dm_config_node *n);
+
+struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem,
+						     const struct dm_config_node *node,
+						     int siblings);
+struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key);
+struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft);
+struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft,
+					    const struct dm_config_node *cn,
+					    int siblings);
+
+struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
+
+
 /* Cookie prefixes.
  * The cookie value consists of a prefix (16 bits) and a base (16 bits).
  * We can use the prefix to store the flags. These flags are sent to
diff -ruN -xCVS cvs-clean/libdm/libdm-config.c cvs-daemons-reorg/libdm/libdm-config.c
--- cvs-clean/libdm/libdm-config.c	1970-01-01 01:00:00.000000000 +0100
+++ cvs-daemons-reorg/libdm/libdm-config.c	2011-08-29 19:49:36.000000000 +0200
@@ -0,0 +1,1236 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
+ *
+ * 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
+ */
+
+#include "dmlib.h"
+
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#define SECTION_B_CHAR '{'
+#define SECTION_E_CHAR '}'
+
+enum {
+	TOK_INT,
+	TOK_FLOAT,
+	TOK_STRING,		/* Single quotes */
+	TOK_STRING_ESCAPED,	/* Double quotes */
+	TOK_EQ,
+	TOK_SECTION_B,
+	TOK_SECTION_E,
+	TOK_ARRAY_B,
+	TOK_ARRAY_E,
+	TOK_IDENTIFIER,
+	TOK_COMMA,
+	TOK_EOF
+};
+
+struct parser {
+	const char *fb, *fe;		/* file limits */
+
+	int t;			/* token limits and type */
+	const char *tb, *te;
+
+	int line;		/* line number we are on */
+
+	struct dm_pool *mem;
+};
+
+struct cs {
+	struct dm_config_tree cft;
+	struct dm_pool *mem;
+	time_t timestamp;
+	off_t st_size;
+	char *filename;
+	int exists;
+	int keep_open;
+	void *custom; /* LVM uses this for a device pointer */
+};
+
+struct output_line {
+	FILE *fp;
+	struct dm_pool *mem;
+	dm_putline_fn putline;
+	void *putline_baton;
+};
+
+static void _get_token(struct parser *p, int tok_prev);
+static void _eat_space(struct parser *p);
+static struct dm_config_node *_file(struct parser *p);
+static struct dm_config_node *_section(struct parser *p);
+static struct dm_config_value *_value(struct parser *p);
+static struct dm_config_value *_type(struct parser *p);
+static int _match_aux(struct parser *p, int t);
+static struct dm_config_value *_create_value(struct dm_pool *mem);
+static struct dm_config_node *_create_node(struct dm_pool *mem);
+static char *_dup_tok(struct parser *p);
+
+static const int sep = '/';
+
+#define MAX_INDENT 32
+
+#define match(t) do {\
+   if (!_match_aux(p, (t))) {\
+	log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
+		  p->tb - p->fb + 1, p->line); \
+      return 0;\
+   } \
+} while(0);
+
+static int _tok_match(const char *str, const char *b, const char *e)
+{
+	while (*str && (b != e)) {
+		if (*str++ != *b++)
+			return 0;
+	}
+
+	return !(*str || (b != e));
+}
+
+/*
+ * public interface
+ */
+struct dm_config_tree *dm_config_create(const char *filename, int keep_open)
+{
+	struct cs *c;
+	struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
+
+	if (!mem) {
+		log_error("Failed to allocate config pool.");
+		return 0;
+	}
+
+	if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
+		log_error("Failed to allocate config tree.");
+		dm_pool_destroy(mem);
+		return 0;
+	}
+
+	c->mem = mem;
+	c->cft.root = (struct dm_config_node *) NULL;
+	c->timestamp = 0;
+	c->exists = 0;
+	c->keep_open = keep_open;
+	c->custom = NULL;
+	if (filename)
+		c->filename = dm_pool_strdup(c->mem, filename);
+	return &c->cft;
+}
+
+void dm_config_set_custom(struct dm_config_tree *cft, void *custom)
+{
+	struct cs *c = (struct cs *) cft;
+	c->custom = custom;
+}
+
+void *dm_config_get_custom(struct dm_config_tree *cft)
+{
+	struct cs *c = (struct cs *) cft;
+	return c->custom;
+}
+
+int dm_config_keep_open(struct dm_config_tree *cft)
+{
+	struct cs *c = (struct cs *) cft;
+	return c->keep_open;
+}
+
+void dm_config_destroy(struct dm_config_tree *cft)
+{
+	struct cs *c = (struct cs *) cft;
+	dm_pool_destroy(c->mem);
+}
+
+int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end)
+{
+	/* TODO? if (start == end) return 1; */
+
+	struct cs *c = (struct cs *) cft;
+	struct parser *p;
+	if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
+		return_0;
+
+	p->mem = c->mem;
+	p->fb = start;
+	p->fe = end;
+	p->tb = p->te = p->fb;
+	p->line = 1;
+
+	_get_token(p, TOK_SECTION_E);
+	if (!(cft->root = _file(p)))
+		return_0;
+
+	return 1;
+}
+
+struct dm_config_tree *dm_config_from_string(const char *config_settings)
+{
+	struct dm_config_tree *cft;
+
+	if (!(cft = dm_config_create(NULL, 0)))
+		return_NULL;
+
+	if (!dm_config_parse(cft, config_settings, config_settings + strlen(config_settings))) {
+		dm_config_destroy(cft);
+		return_NULL;
+	}
+
+	return cft;
+}
+
+int dm_config_check_file(struct dm_config_tree *cft, const char **filename, struct stat *info)
+{
+	struct cs *c = (struct cs *) cft;
+	struct stat _info;
+	if (!info)
+		info = &_info;
+	if (filename)
+		*filename = c->filename;
+
+	if (stat(c->filename, info)) {
+		log_sys_error("stat", c->filename);
+		c->exists = 0;
+		return 0;
+	}
+
+	if (!S_ISREG(info->st_mode)) {
+		log_error("%s is not a regular file", c->filename);
+		c->exists = 0;
+		return 0;
+	}
+
+	c->exists = 1;
+
+	if (info->st_size == 0)
+		log_verbose("%s is empty", c->filename);
+
+	c->timestamp = info->st_ctime;
+	c->st_size = info->st_size;
+
+	return 1;
+}
+
+time_t dm_config_timestamp(struct dm_config_tree *cft)
+{
+	struct cs *c = (struct cs *) cft;
+	return c->timestamp;
+}
+
+/*
+ * Return 1 if config files ought to be reloaded
+ */
+int dm_config_changed(struct dm_config_tree *cft)
+{
+	struct cs *c = (struct cs *) cft;
+	struct stat info;
+
+	if (!c->filename)
+		return 0;
+
+	if (stat(c->filename, &info) == -1) {
+		/* Ignore a deleted config file: still use original data */
+		if (errno == ENOENT) {
+			if (!c->exists)
+				return 0;
+			log_very_verbose("Config file %s has disappeared!",
+					 c->filename);
+			goto reload;
+		}
+		log_sys_error("stat", c->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",
+			  c->filename);
+		goto reload;
+	}
+
+	/* Unchanged? */
+	if (c->timestamp == info.st_ctime && c->st_size == info.st_size)
+		return 0;
+
+      reload:
+	log_verbose("Detected config file change to %s", c->filename);
+	return 1;
+}
+
+static int _line_start(struct output_line *outline)
+{
+	if (!dm_pool_begin_object(outline->mem, 128)) {
+		log_error("dm_pool_begin_object failed for config line");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int _line_append(struct output_line *outline, const char *fmt, ...)
+  __attribute__ ((format(printf, 2, 3)));
+static int _line_append(struct output_line *outline, const char *fmt, ...)
+{
+	char buf[4096];
+	va_list ap;
+	int n;
+
+	va_start(ap, fmt);
+	n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
+	va_end(ap);
+
+	if (n < 0 || n > (int) sizeof buf - 1) {
+		log_error("vsnprintf failed for config line");
+		return 0;
+	}
+
+	if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
+		log_error("dm_pool_grow_object failed for config line");
+		return 0;
+	}
+
+	return 1;
+}
+
+#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
+
+static int _line_end(struct output_line *outline)
+{
+	const char *line;
+
+	if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
+		log_error("dm_pool_grow_object failed for config line");
+		return 0;
+	}
+
+	line = dm_pool_end_object(outline->mem);
+	if (outline->putline)
+		outline->putline(line, outline->putline_baton);
+	else {
+		if (!outline->fp)
+			log_print("%s", line);
+		else
+			fprintf(outline->fp, "%s\n", line);
+	}
+
+	return 1;
+}
+
+static int _write_value(struct output_line *outline, const struct dm_config_value *v)
+{
+	char *buf;
+
+	switch (v->type) {
+	case DM_CFG_STRING:
+		if (!(buf = alloca(dm_escaped_len(v->v.str)))) {
+			log_error("temporary stack allocation for a config "
+				  "string failed");
+			return 0;
+		}
+		line_append("\"%s\"", dm_escape_double_quotes(buf, v->v.str));
+		break;
+
+	case DM_CFG_FLOAT:
+		line_append("%f", v->v.r);
+		break;
+
+	case DM_CFG_INT:
+		line_append("%" PRId64, v->v.i);
+		break;
+
+	case DM_CFG_EMPTY_ARRAY:
+		line_append("[]");
+		break;
+
+	default:
+		log_error("_write_value: Unknown value type: %d", v->type);
+
+	}
+
+	return 1;
+}
+
+static int _write_config(const struct dm_config_node *n, int only_one,
+			 struct output_line *outline, int level)
+{
+	char space[MAX_INDENT + 1];
+	int l = (level < MAX_INDENT) ? level : MAX_INDENT;
+	int i;
+
+	if (!n)
+		return 1;
+
+	for (i = 0; i < l; i++)
+		space[i] = '\t';
+	space[i] = '\0';
+
+	do {
+		if (!_line_start(outline))
+			return_0;
+		line_append("%s%s", space, n->key);
+		if (!n->v) {
+			/* it's a sub section */
+			line_append(" {");
+			if (!_line_end(outline))
+				return_0;
+			_write_config(n->child, 0, outline, level + 1);
+			if (!_line_start(outline))
+				return_0;
+			line_append("%s}", space);
+		} else {
+			/* it's a value */
+			const struct dm_config_value *v = n->v;
+			line_append("=");
+			if (v->next) {
+				line_append("[");
+				while (v && v->type != DM_CFG_EMPTY_ARRAY) {
+					if (!_write_value(outline, v))
+						return_0;
+					v = v->next;
+					if (v && v->type != DM_CFG_EMPTY_ARRAY)
+						line_append(", ");
+				}
+				line_append("]");
+			} else
+				if (!_write_value(outline, v))
+					return_0;
+		}
+		if (!_line_end(outline))
+			return_0;
+		n = n->sib;
+	} while (n && !only_one);
+	/* FIXME: add error checking */
+	return 1;
+}
+
+int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton)
+{
+	struct output_line outline;
+	outline.fp = NULL;
+	if (!(outline.mem = dm_pool_create("config_line", 1024)))
+		return_0;
+	outline.putline = putline;
+	outline.putline_baton = baton;
+	if (!_write_config(cn, 0, &outline, 0)) {
+		dm_pool_destroy(outline.mem);
+		return_0;
+	}
+	dm_pool_destroy(outline.mem);
+	return 1;
+}
+
+int dm_config_write(struct dm_config_tree *cft, const char *file,
+		    int argc, char **argv)
+{
+	const struct dm_config_node *cn;
+	int r = 1;
+	struct output_line outline;
+	outline.fp = NULL;
+	outline.putline = NULL;
+
+	if (!file)
+		file = "stdout";
+	else if (!(outline.fp = fopen(file, "w"))) {
+		log_sys_error("open", file);
+		return 0;
+	}
+
+	if (!(outline.mem = dm_pool_create("config_line", 1024))) {
+		r = 0;
+		goto_out;
+	}
+
+	log_verbose("Dumping configuration to %s", file);
+	if (!argc) {
+		if (!_write_config(cft->root, 0, &outline, 0)) {
+			log_error("Failure while writing to %s", file);
+			r = 0;
+		}
+	} else while (argc--) {
+		if ((cn = dm_config_find_node(cft->root, *argv))) {
+			if (!_write_config(cn, 1, &outline, 0)) {
+				log_error("Failure while writing to %s", file);
+				r = 0;
+			}
+		} else {
+			log_error("Configuration node %s not found", *argv);
+			r = 0;
+		}
+		argv++;
+	}
+
+	dm_pool_destroy(outline.mem);
+
+out:
+	if (outline.fp && dm_fclose(outline.fp)) {
+		stack;
+		r = 0;
+	}
+
+	return r;
+}
+
+/*
+ * parser
+ */
+static struct dm_config_node *_file(struct parser *p)
+{
+	struct dm_config_node *root = NULL, *n, *l = NULL;
+	while (p->t != TOK_EOF) {
+		if (!(n = _section(p)))
+			return_0;
+
+		if (!root)
+			root = n;
+		else
+			l->sib = n;
+		n->parent = root;
+		l = n;
+	}
+	return root;
+}
+
+static struct dm_config_node *_section(struct parser *p)
+{
+	/* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
+	struct dm_config_node *root, *n, *l = NULL;
+	if (!(root = _create_node(p->mem)))
+		return_0;
+
+	if (!(root->key = _dup_tok(p)))
+		return_0;
+
+	match(TOK_IDENTIFIER);
+
+	if (p->t == TOK_SECTION_B) {
+		match(TOK_SECTION_B);
+		while (p->t != TOK_SECTION_E) {
+			if (!(n = _section(p)))
+				return_0;
+
+			if (!root->child)
+				root->child = n;
+			else
+				l->sib = n;
+			n->parent = root;
+			l = n;
+		}
+		match(TOK_SECTION_E);
+	} else {
+		match(TOK_EQ);
+		if (!(root->v = _value(p)))
+			return_0;
+	}
+
+	return root;
+}
+
+static struct dm_config_value *_value(struct parser *p)
+{
+	/* '[' TYPE* ']' | TYPE */
+	struct dm_config_value *h = NULL, *l, *ll = NULL;
+	if (p->t == TOK_ARRAY_B) {
+		match(TOK_ARRAY_B);
+		while (p->t != TOK_ARRAY_E) {
+			if (!(l = _type(p)))
+				return_0;
+
+			if (!h)
+				h = l;
+			else
+				ll->next = l;
+			ll = l;
+
+			if (p->t == TOK_COMMA)
+				match(TOK_COMMA);
+		}
+		match(TOK_ARRAY_E);
+		/*
+		 * Special case for an empty array.
+		 */
+		if (!h) {
+			if (!(h = _create_value(p->mem)))
+				return NULL;
+
+			h->type = DM_CFG_EMPTY_ARRAY;
+		}
+
+	} else
+		h = _type(p);
+
+	return h;
+}
+
+static struct dm_config_value *_type(struct parser *p)
+{
+	/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
+	struct dm_config_value *v = _create_value(p->mem);
+	char *str;
+
+	if (!v)
+		return NULL;
+
+	switch (p->t) {
+	case TOK_INT:
+		v->type = DM_CFG_INT;
+		v->v.i = strtoll(p->tb, NULL, 0);	/* FIXME: check error */
+		match(TOK_INT);
+		break;
+
+	case TOK_FLOAT:
+		v->type = DM_CFG_FLOAT;
+		v->v.r = strtod(p->tb, NULL);	/* FIXME: check error */
+		match(TOK_FLOAT);
+		break;
+
+	case TOK_STRING:
+		v->type = DM_CFG_STRING;
+
+		p->tb++, p->te--;	/* strip "'s */
+		if (!(v->v.str = _dup_tok(p)))
+			return_0;
+		p->te++;
+		match(TOK_STRING);
+		break;
+
+	case TOK_STRING_ESCAPED:
+		v->type = DM_CFG_STRING;
+
+		p->tb++, p->te--;	/* strip "'s */
+		if (!(str = _dup_tok(p)))
+			return_0;
+		dm_unescape_double_quotes(str);
+		v->v.str = str;
+		p->te++;
+		match(TOK_STRING_ESCAPED);
+		break;
+
+	default:
+		log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
+			  p->tb - p->fb + 1, p->line);
+		return 0;
+	}
+	return v;
+}
+
+static int _match_aux(struct parser *p, int t)
+{
+	if (p->t != t)
+		return 0;
+
+	_get_token(p, t);
+	return 1;
+}
+
+/*
+ * tokeniser
+ */
+static void _get_token(struct parser *p, int tok_prev)
+{
+	int values_allowed = 0;
+
+	const char *te;
+
+	p->tb = p->te;
+	_eat_space(p);
+	if (p->tb == p->fe || !*p->tb) {
+		p->t = TOK_EOF;
+		return;
+	}
+
+	/* Should next token be interpreted as value instead of identifier? */
+	if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
+	    tok_prev == TOK_COMMA)
+		values_allowed = 1;
+
+	p->t = TOK_INT;		/* fudge so the fall through for
+				   floats works */
+
+	te = p->te;
+	switch (*te) {
+	case SECTION_B_CHAR:
+		p->t = TOK_SECTION_B;
+		te++;
+		break;
+
+	case SECTION_E_CHAR:
+		p->t = TOK_SECTION_E;
+		te++;
+		break;
+
+	case '[':
+		p->t = TOK_ARRAY_B;
+		te++;
+		break;
+
+	case ']':
+		p->t = TOK_ARRAY_E;
+		te++;
+		break;
+
+	case ',':
+		p->t = TOK_COMMA;
+		te++;
+		break;
+
+	case '=':
+		p->t = TOK_EQ;
+		te++;
+		break;
+
+	case '"':
+		p->t = TOK_STRING_ESCAPED;
+		te++;
+		while ((te != p->fe) && (*te) && (*te != '"')) {
+			if ((*te == '\\') && (te + 1 != p->fe) &&
+			    *(te + 1))
+				te++;
+			te++;
+		}
+
+		if ((te != p->fe) && (*te))
+			te++;
+		break;
+
+	case '\'':
+		p->t = TOK_STRING;
+		te++;
+		while ((te != p->fe) && (*te) && (*te != '\''))
+			te++;
+
+		if ((te != p->fe) && (*te))
+			te++;
+		break;
+
+	case '.':
+		p->t = TOK_FLOAT;
+		/* Fall through */
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	case '+':
+	case '-':
+		if (values_allowed) {
+			while (++te != p->fe) {
+				if (!isdigit((int) *te)) {
+					if (*te == '.') {
+						if (p->t != TOK_FLOAT) {
+							p->t = TOK_FLOAT;
+							continue;
+						}
+					}
+					break;
+				}
+			}
+			break;
+		}
+		/* fall through */
+
+	default:
+		p->t = TOK_IDENTIFIER;
+		while ((te != p->fe) && (*te) && !isspace(*te) &&
+		       (*te != '#') && (*te != '=') &&
+		       (*te != SECTION_B_CHAR) &&
+		       (*te != SECTION_E_CHAR))
+			te++;
+		break;
+	}
+
+	p->te = te;
+}
+
+static void _eat_space(struct parser *p)
+{
+	while (p->tb != p->fe) {
+		if (*p->te == '#')
+			while ((p->te != p->fe) && (*p->te != '\n') && (*p->te))
+				++p->te;
+
+		else if (!isspace(*p->te))
+			break;
+
+		while ((p->te != p->fe) && isspace(*p->te)) {
+			if (*p->te == '\n')
+				++p->line;
+			++p->te;
+		}
+
+		p->tb = p->te;
+	}
+}
+
+/*
+ * memory management
+ */
+static struct dm_config_value *_create_value(struct dm_pool *mem)
+{
+	return dm_pool_zalloc(mem, sizeof(struct dm_config_value));
+}
+
+static struct dm_config_node *_create_node(struct dm_pool *mem)
+{
+	return dm_pool_zalloc(mem, sizeof(struct dm_config_node));
+}
+
+static char *_dup_tok(struct parser *p)
+{
+	size_t len = p->te - p->tb;
+	char *str = dm_pool_alloc(p->mem, len + 1);
+	if (!str) {
+		log_error("Failed to duplicate token.");
+		return 0;
+	}
+	memcpy(str, p->tb, len);
+	str[len] = '\0';
+	return str;
+}
+
+/*
+ * utility functions
+ */
+static const struct dm_config_node *_find_config_node(const void *start,
+						      const char *path)
+{
+	const char *e;
+	const struct dm_config_node *cn = start;
+	const struct dm_config_node *cn_found = NULL;
+
+	while (cn) {
+		/* trim any leading slashes */
+		while (*path && (*path == sep))
+			path++;
+
+		/* find the end of this segment */
+		for (e = path; *e && (*e != sep); e++) ;
+
+		/* hunt for the node */
+		cn_found = NULL;
+		while (cn) {
+			if (_tok_match(cn->key, path, e)) {
+				/* Inefficient */
+				if (!cn_found)
+					cn_found = cn;
+				else
+					log_warn("WARNING: Ignoring duplicate"
+						 " config node: %s ("
+						 "seeking %s)", cn->key, path);
+			}
+
+			cn = cn->sib;
+		}
+
+		if (cn_found && *e)
+			cn = cn_found->child;
+		else
+			break;	/* don't move into the last node */
+
+		path = e;
+	}
+
+	return cn_found;
+}
+
+typedef const struct dm_config_node *_node_lookup_fn(const void *start, const char *path);
+
+static const struct dm_config_node *_find_first_config_node(const void *start, const char *path)
+{
+	const struct dm_config_tree *cft = start;
+	const struct dm_config_node *cn = NULL;
+
+	while (cft) {
+		if ((cn = _find_config_node(cft->root, path)))
+			return cn;
+		cft = cft->cascade;
+	}
+
+	return NULL;
+}
+
+static const char *_find_config_str(const void *start, _node_lookup_fn find,
+				    const char *path, const char *fail)
+{
+	const struct dm_config_node *n = find(start, path);
+
+	/* Empty strings are ignored */
+	if ((n && n->v && n->v->type == DM_CFG_STRING) && (*n->v->v.str)) {
+		log_very_verbose("Setting %s to %s", path, n->v->v.str);
+		return n->v->v.str;
+	}
+
+	if (fail)
+		log_very_verbose("%s not found in config: defaulting to %s",
+				 path, fail);
+	return fail;
+}
+
+const char *dm_config_find_str(const struct dm_config_node *cn,
+			       const char *path, const char *fail)
+{
+	return _find_config_str(cn, _find_config_node, path, fail);
+}
+
+static int64_t _find_config_int64(const void *start, _node_lookup_fn find,
+				  const char *path, int64_t fail)
+{
+	const struct dm_config_node *n = find(start, path);
+
+	if (n && n->v && n->v->type == DM_CFG_INT) {
+		log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
+		return n->v->v.i;
+	}
+
+	log_very_verbose("%s not found in config: defaulting to %" PRId64,
+			 path, fail);
+	return fail;
+}
+
+static float _find_config_float(const void *start, _node_lookup_fn find,
+				const char *path, float fail)
+{
+	const struct dm_config_node *n = find(start, path);
+
+	if (n && n->v && n->v->type == DM_CFG_FLOAT) {
+		log_very_verbose("Setting %s to %f", path, n->v->v.r);
+		return n->v->v.r;
+	}
+
+	log_very_verbose("%s not found in config: defaulting to %f",
+			 path, fail);
+
+	return fail;
+
+}
+
+static int _str_in_array(const char *str, const char * const values[])
+{
+	int i;
+
+	for (i = 0; values[i]; i++)
+		if (!strcasecmp(str, values[i]))
+			return 1;
+
+	return 0;
+}
+
+static int _str_to_bool(const char *str, int fail)
+{
+	const char * const _true_values[]  = { "y", "yes", "on", "true", NULL };
+	const char * const _false_values[] = { "n", "no", "off", "false", NULL };
+
+	if (_str_in_array(str, _true_values))
+		return 1;
+
+	if (_str_in_array(str, _false_values))
+		return 0;
+
+	return fail;
+}
+
+static int _find_config_bool(const void *start, _node_lookup_fn find,
+			     const char *path, int fail)
+{
+	const struct dm_config_node *n = find(start, path);
+	const struct dm_config_value *v;
+
+	if (!n)
+		return fail;
+
+	v = n->v;
+
+	switch (v->type) {
+	case DM_CFG_INT:
+		return v->v.i ? 1 : 0;
+
+	case DM_CFG_STRING:
+		return _str_to_bool(v->v.str, fail);
+	}
+
+	return fail;
+}
+
+/***********************************
+ * node-based lookup
+ **/
+
+const struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn,
+						 const char *path)
+{
+	return _find_config_node(cn, path);
+}
+
+int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail)
+{
+	/* FIXME Add log_error message on overflow */
+	return (int) _find_config_int64(cn, _find_config_node, path, (int64_t) fail);
+}
+
+float dm_config_find_float(const struct dm_config_node *cn, const char *path,
+			   float fail)
+{
+	return _find_config_float(cn, _find_config_node, path, fail);
+}
+
+int dm_config_find_bool(const struct dm_config_node *cn, const char *path, int fail)
+{
+	return _find_config_bool(cn, _find_config_node, path, fail);
+}
+
+/***********************************
+ * tree-based lookup
+ **/
+
+const struct dm_config_node *dm_config_tree_find_node(const struct dm_config_tree *cft,
+						      const char *path)
+{
+	return _find_first_config_node(cft, path);
+}
+
+const char *dm_config_tree_find_str(const struct dm_config_tree *cft, const char *path,
+				    const char *fail)
+{
+	return _find_config_str(cft, _find_first_config_node, path, fail);
+}
+
+int dm_config_tree_find_int(const struct dm_config_tree *cft, const char *path, int fail)
+{
+	/* FIXME Add log_error message on overflow */
+	return (int) _find_config_int64(cft, _find_first_config_node, path, (int64_t) fail);
+}
+
+int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft, const char *path, int64_t fail)
+{
+	return _find_config_int64(cft, _find_first_config_node, path, fail);
+}
+
+float dm_config_tree_find_float(const struct dm_config_tree *cft, const char *path,
+				float fail)
+{
+	return _find_config_float(cft, _find_first_config_node, path, fail);
+}
+
+int dm_config_tree_find_bool(const struct dm_config_tree *cft, const char *path, int fail)
+{
+	return _find_config_bool(cft, _find_first_config_node, path, fail);
+}
+
+/************************************/
+
+
+int dm_config_get_uint32(const struct dm_config_node *cn, const char *path,
+			      uint32_t *result)
+{
+	const struct dm_config_node *n;
+
+	n = dm_config_find_node(cn, path);
+
+	if (!n || !n->v || n->v->type != DM_CFG_INT)
+		return 0;
+
+	*result = n->v->v.i;
+	return 1;
+}
+
+int dm_config_get_uint64(const struct dm_config_node *cn, const char *path,
+			 uint64_t *result)
+{
+	const struct dm_config_node *n;
+
+	n = dm_config_find_node(cn, path);
+
+	if (!n || !n->v || n->v->type != DM_CFG_INT)
+		return 0;
+
+	*result = (uint64_t) n->v->v.i;
+	return 1;
+}
+
+int dm_config_get_str(const struct dm_config_node *cn, const char *path,
+		      const char **result)
+{
+	const struct dm_config_node *n;
+
+	n = dm_config_find_node(cn, path);
+
+	if (!n || !n->v || n->v->type != DM_CFG_STRING)
+		return 0;
+
+	*result = n->v->v.str;
+	return 1;
+}
+
+/*
+ * Convert a token type to the char it represents.
+ */
+static char _token_type_to_char(int type)
+{
+	switch (type) {
+		case TOK_SECTION_B:
+			return SECTION_B_CHAR;
+		case TOK_SECTION_E:
+			return SECTION_E_CHAR;
+		default:
+			return 0;
+	}
+}
+
+/*
+ * Returns:
+ *  # of 'type' tokens in 'str'.
+ */
+static unsigned _count_tokens(const char *str, unsigned len, int type)
+{
+	char c;
+
+	c = _token_type_to_char(type);
+
+	return dm_count_chars(str, len, c);
+}
+
+const char *dm_config_parent_name(const struct dm_config_node *n)
+{
+	return (n->parent ? n->parent->key : "(root)");
+}
+/*
+ * Heuristic function to make a quick guess as to whether a text
+ * region probably contains a valid config "section".  (Useful for
+ * scanning areas of the disk for old metadata.)
+ * Config sections contain various tokens, may contain other sections
+ * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
+ * end (type 'TOK_SECTION_E') tokens.  As a quick heuristic, we just
+ * count the number of begin and end tokens, and see if they are
+ * non-zero and the counts match.
+ * Full validation of the section should be done with another function
+ * (for example, read_config_fd).
+ *
+ * Returns:
+ *  0 - probably is not a valid config section
+ *  1 - probably _is_ a valid config section
+ */
+unsigned dm_config_maybe_section(const char *str, unsigned len)
+{
+	int begin_count;
+	int end_count;
+
+	begin_count = _count_tokens(str, len, TOK_SECTION_B);
+	end_count = _count_tokens(str, len, TOK_SECTION_E);
+
+	if (begin_count && end_count && (begin_count == end_count))
+		return 1;
+	else
+		return 0;
+}
+
+static struct dm_config_value *_clone_config_value(struct dm_pool *mem,
+						   const struct dm_config_value *v)
+{
+	struct dm_config_value *new_cv;
+
+	if (!v)
+		return NULL;
+
+	if (!(new_cv = _create_value(mem))) {
+		log_error("Failed to clone config value.");
+		return NULL;
+	}
+
+	new_cv->type = v->type;
+	if (v->type == DM_CFG_STRING) {
+		if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
+			log_error("Failed to clone config string value.");
+			return NULL;
+		}
+	} else
+		new_cv->v = v->v;
+
+	if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
+		return_NULL;
+
+	return new_cv;
+}
+
+struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *cn, int siblings)
+{
+	struct dm_config_node *new_cn;
+
+	if (!cn)
+		return NULL;
+
+	if (!(new_cn = _create_node(mem))) {
+		log_error("Failed to clone config node.");
+		return NULL;
+	}
+
+	if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
+		log_error("Failed to clone config node key.");
+		return NULL;
+	}
+
+	if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
+	    (cn->child && !(new_cn->child = dm_config_clone_node_with_mem(mem, cn->child, 1))) ||
+	    (siblings && cn->sib && !(new_cn->sib = dm_config_clone_node_with_mem(mem, cn->sib, siblings))))
+		return_NULL; /* 'new_cn' released with mem pool */
+
+	return new_cn;
+}
+
+struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *node, int sib)
+{
+	struct cs *c = (struct cs *) cft;
+	return dm_config_clone_node_with_mem(c->mem, node, sib);
+}
+
+struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key)
+{
+	struct cs *c = (struct cs *) cft;
+	struct dm_config_node *cn;
+
+	if (!(cn = _create_node(c->mem))) {
+		log_error("Failed to create config node.");
+		return NULL;
+	}
+	if (!(cn->key = dm_pool_strdup(c->mem, key))) {
+		log_error("Failed to create config node's key.");
+		return NULL;
+	}
+	if (!(cn->v = _create_value(c->mem))) {
+		log_error("Failed to create config node's value.");
+		return NULL;
+	}
+	cn->parent = NULL;
+	cn->v->type = DM_CFG_INT;
+	cn->v->v.i = 0;
+	cn->v->next = NULL;
+	return cn;
+}
+
+struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft)
+{
+	struct cs *c = (struct cs *) cft;
+	return _create_value(c->mem);
+}
+
+struct dm_pool *dm_config_memory(struct dm_config_tree *cft)
+{
+	struct cs *c = (struct cs *) cft;
+	return c->mem;
+}
diff -ruN -xCVS cvs-clean/libdm/libdm-string.c cvs-daemons-reorg/libdm/libdm-string.c
--- cvs-clean/libdm/libdm-string.c	2010-11-23 16:00:52.000000000 +0100
+++ cvs-daemons-reorg/libdm/libdm-string.c	2011-08-29 16:37:01.000000000 +0200
@@ -161,3 +161,225 @@
 	dm_free(buf);
 	return n + 1;
 }
+
+/*
+ * Count occurences of 'c' in 'str' until we reach a null char.
+ *
+ * Returns:
+ *  len - incremented for each char we encounter.
+ *  count - number of occurrences of 'c' and 'c2'.
+ */
+static void _count_chars(const char *str, size_t *len, int *count,
+			 const int c1, const int c2)
+{
+	const char *ptr;
+
+	for (ptr = str; *ptr; ptr++, (*len)++)
+		if (*ptr == c1 || *ptr == c2)
+			(*count)++;
+}
+
+unsigned dm_count_chars(const char *str, size_t len, const int c)
+{
+	size_t i;
+	unsigned count = 0;
+
+	for (i = 0; i < len; i++)
+		if (str[i] == c)
+			count++;
+
+	return count;
+}
+
+size_t dm_escaped_len(const char *str)
+{
+	size_t len = 1;
+	int count = 0;
+
+	_count_chars(str, &len, &count, '\"', '\\');
+
+	return count + len;
+}
+
+/*
+ * Copies a string, quoting orig_char with quote_char.
+ * Optionally also quote quote_char.
+ */
+static void _quote_characters(char **out, const char *src,
+			      const int orig_char, const int quote_char,
+			      int quote_quote_char)
+{
+	while (*src) {
+		if (*src == orig_char ||
+		    (*src == quote_char && quote_quote_char))
+			*(*out)++ = quote_char;
+
+		*(*out)++ = *src++;
+	}
+}
+
+static void _unquote_one_character(char *src, const char orig_char,
+				   const char quote_char)
+{
+	char *out;
+	char s, n;
+
+	/* Optimise for the common case where no changes are needed. */
+	while ((s = *src++)) {
+		if (s == quote_char &&
+		    ((n = *src) == orig_char || n == quote_char)) {
+			out = src++;
+			*(out - 1) = n;
+
+			while ((s = *src++)) {
+				if (s == quote_char &&
+				    ((n = *src) == orig_char || n == quote_char)) {
+					s = n;
+					src++;
+				}
+				*out = s;
+				out++;
+			}
+
+			*out = '\0';
+			return;
+		}
+	}
+}
+
+/*
+ * Unquote each character given in orig_char array and unquote quote_char
+ * as well. Also save the first occurrence of each character from orig_char
+ * that was found unquoted in arr_substr_first_unquoted array. This way we can
+ * process several characters in one go.
+ */
+static void _unquote_characters(char *src, const char *orig_chars,
+				size_t num_orig_chars,
+				const char quote_char,
+				char *arr_substr_first_unquoted[])
+{
+	char *out = src;
+	char c, s, n;
+	unsigned i;
+
+	while ((s = *src++)) {
+		for (i = 0; i < num_orig_chars; i++) {
+			c = orig_chars[i];
+			if (s == quote_char &&
+			    ((n = *src) == c || n == quote_char)) {
+				s = n;
+				src++;
+				break;
+			}
+			if (arr_substr_first_unquoted && (s == c) &&
+			    !arr_substr_first_unquoted[i])
+				arr_substr_first_unquoted[i] = out;
+		};
+		*out++ = s;
+	}
+
+	*out = '\0';
+}
+
+/*
+ * Copies a string, quoting hyphens with hyphens.
+ */
+static void _quote_hyphens(char **out, const char *src)
+{
+	_quote_characters(out, src, '-', '-', 0);
+}
+
+char *dm_build_dm_name(struct dm_pool *mem, const char *vgname,
+		       const char *lvname, const char *layer)
+{
+	size_t len = 1;
+	int hyphens = 1;
+	char *r, *out;
+
+	_count_chars(vgname, &len, &hyphens, '-', 0);
+	_count_chars(lvname, &len, &hyphens, '-', 0);
+
+	if (layer && *layer) {
+		_count_chars(layer, &len, &hyphens, '-', 0);
+		hyphens++;
+	}
+
+	len += hyphens;
+
+	if (!(r = dm_pool_alloc(mem, len))) {
+		log_error("build_dm_name: Allocation failed for %" PRIsize_t
+			  " for %s %s %s.", len, vgname, lvname, layer);
+		return NULL;
+	}
+
+	out = r;
+	_quote_hyphens(&out, vgname);
+	*out++ = '-';
+	_quote_hyphens(&out, lvname);
+
+	if (layer && *layer) {
+		/* No hyphen if the layer begins with _ e.g. _mlog */
+		if (*layer != '_')
+			*out++ = '-';
+		_quote_hyphens(&out, layer);
+	}
+	*out = '\0';
+
+	return r;
+}
+
+char *dm_build_dm_uuid(struct dm_pool *mem, const char *prefix, const char *lvid, const char *layer)
+{
+	char *dmuuid;
+	size_t len;
+
+	if (!layer)
+		layer = "";
+
+	len = strlen(prefix) + strlen(lvid) + strlen(layer) + 1;
+
+	if (!(dmuuid = dm_pool_alloc(mem, len))) {
+		log_error("build_dm_name: Allocation failed for %" PRIsize_t
+			  " %s %s.", len, lvid, layer);
+		return NULL;
+	}
+
+	sprintf(dmuuid, "%s%s%s%s", prefix, lvid, (*layer) ? "-" : "", layer);
+
+	return dmuuid;
+}
+
+/*
+ * Copies a string, quoting double quotes with backslashes.
+ */
+char *dm_escape_double_quotes(char *out, const char *src)
+{
+	char *buf = out;
+
+	_quote_characters(&buf, src, '\"', '\\', 1);
+	*buf = '\0';
+
+	return out;
+}
+
+void dm_unescape_double_quotes(char *src)
+{
+	_unquote_one_character(src, '\"', '\\');
+}
+
+void dm_unescape_colons_and_at_signs(char *src,
+				     char **substr_first_unquoted_colon,
+				     char **substr_first_unquoted_at_sign)
+{
+	const char *orig_chars = ":@";
+	char *arr_substr_first_unquoted[] = {NULL, NULL, NULL};
+
+	_unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted);
+
+	if (substr_first_unquoted_colon)
+		*substr_first_unquoted_colon = arr_substr_first_unquoted[0];
+
+	if (substr_first_unquoted_at_sign)
+		*substr_first_unquoted_at_sign = arr_substr_first_unquoted[1];
+}
+
diff -ruN -xCVS cvs-clean/libdm/Makefile.in cvs-daemons-reorg/libdm/Makefile.in
--- cvs-clean/libdm/Makefile.in	2010-08-03 15:00:46.000000000 +0200
+++ cvs-daemons-reorg/libdm/Makefile.in	2011-08-29 15:57:58.000000000 +0200
@@ -25,6 +25,7 @@
 	libdm-deptree.c \
 	libdm-string.c \
 	libdm-report.c \
+	libdm-config.c \
 	mm/dbg_malloc.c \
 	mm/pool.c \
 	regex/matcher.c \
diff -ruN -xCVS cvs-clean/tools/dumpconfig.c cvs-daemons-reorg/tools/dumpconfig.c
--- cvs-clean/tools/dumpconfig.c	2009-11-03 16:50:43.000000000 +0100
+++ cvs-daemons-reorg/tools/dumpconfig.c	2011-08-29 18:34:43.000000000 +0200
@@ -19,7 +19,7 @@
 {
 	const char *file = arg_str_value(cmd, file_ARG, NULL);
 
-	if (!write_config_file(cmd->cft, file, argc, argv)) {
+	if (!dm_config_write(cmd->cft, file, argc, argv)) {
 		stack;
 		return ECMD_FAILED;
 	}
diff -ruN -xCVS cvs-clean/tools/pvchange.c cvs-daemons-reorg/tools/pvchange.c
--- cvs-clean/tools/pvchange.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/tools/pvchange.c	2011-08-29 18:34:44.000000000 +0200
@@ -209,7 +209,7 @@
 		log_verbose("Using physical volume(s) on command line");
 		for (; opt < argc; opt++) {
 			pv_name = argv[opt];
-			unescape_colons_and_at_signs(pv_name, NULL, NULL);
+			dm_unescape_colons_and_at_signs(pv_name, NULL, NULL);
 			vg_name = find_vgname_from_pvname(cmd, pv_name);
 			if (!vg_name) {
 				log_error("Failed to read physical volume %s",
diff -ruN -xCVS cvs-clean/tools/pvck.c cvs-daemons-reorg/tools/pvck.c
--- cvs-clean/tools/pvck.c	2010-09-23 14:02:34.000000000 +0200
+++ cvs-daemons-reorg/tools/pvck.c	2011-08-29 18:34:44.000000000 +0200
@@ -31,7 +31,7 @@
 		/* FIXME: warning and/or check if in use? */
 		log_verbose("Scanning %s", argv[i]);
 
-		unescape_colons_and_at_signs(argv[i], NULL, NULL);
+		dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
 		pv_analyze(cmd, argv[i],
 			   arg_uint64_value(cmd, labelsector_ARG,
 					   UINT64_C(0)));
diff -ruN -xCVS cvs-clean/tools/pvcreate.c cvs-daemons-reorg/tools/pvcreate.c
--- cvs-clean/tools/pvcreate.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/tools/pvcreate.c	2011-08-29 18:34:43.000000000 +0200
@@ -110,7 +110,7 @@
 			return ECMD_FAILED;
 		}
 
-		unescape_colons_and_at_signs(argv[i], NULL, NULL);
+		dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
 
 		if (!(pv = pvcreate_single(cmd, argv[i], &pp, 1))) {
 			stack;
diff -ruN -xCVS cvs-clean/tools/pvmove.c cvs-daemons-reorg/tools/pvmove.c
--- cvs-clean/tools/pvmove.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/tools/pvmove.c	2011-08-29 18:34:44.000000000 +0200
@@ -664,7 +664,7 @@
 			return ECMD_FAILED;
 		}
 
-		unescape_colons_and_at_signs(pv_name, &colon, NULL);
+		dm_unescape_colons_and_at_signs(pv_name, &colon, NULL);
 
 		/* Drop any PE lists from PV name */
 		if (colon)
diff -ruN -xCVS cvs-clean/tools/pvremove.c cvs-daemons-reorg/tools/pvremove.c
--- cvs-clean/tools/pvremove.c	2011-06-15 14:30:25.000000000 +0200
+++ cvs-daemons-reorg/tools/pvremove.c	2011-08-29 18:34:43.000000000 +0200
@@ -150,7 +150,7 @@
 	}
 
 	for (i = 0; i < argc; i++) {
-		unescape_colons_and_at_signs(argv[i], NULL, NULL);
+		dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
 		r = pvremove_single(cmd, argv[i], NULL);
 		if (r > ret)
 			ret = r;
diff -ruN -xCVS cvs-clean/tools/toollib.c cvs-daemons-reorg/tools/toollib.c
--- cvs-clean/tools/toollib.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/tools/toollib.c	2011-08-29 18:34:44.000000000 +0200
@@ -707,7 +707,7 @@
 	if (argc) {
 		log_verbose("Using physical volume(s) on command line");
 		for (; opt < argc; opt++) {
-			unescape_colons_and_at_signs(argv[opt], NULL, &at_sign);
+			dm_unescape_colons_and_at_signs(argv[opt], NULL, &at_sign);
 			if (at_sign && (at_sign == argv[opt])) {
 				tagname = at_sign + 1;
 
@@ -1129,7 +1129,7 @@
 	dm_list_init(&arg_pvnames);
 
 	for (i = 0; i < argc; i++) {
-		unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
+		dm_unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
 
 		if (at_sign && (at_sign == argv[i])) {
 			tagname = at_sign + 1;
diff -ruN -xCVS cvs-clean/tools/vgsplit.c cvs-daemons-reorg/tools/vgsplit.c
--- cvs-clean/tools/vgsplit.c	2011-08-29 19:54:01.000000000 +0200
+++ cvs-daemons-reorg/tools/vgsplit.c	2011-08-29 18:34:43.000000000 +0200
@@ -395,7 +395,7 @@
 
 	/* Move PVs across to new structure */
 	for (opt = 0; opt < argc; opt++) {
-		unescape_colons_and_at_signs(argv[opt], NULL, NULL);
+		dm_unescape_colons_and_at_signs(argv[opt], NULL, NULL);
 		if (!move_pv(vg_from, vg_to, argv[opt]))
 			goto_bad;
 	}
-- 
id' Ash = Ash; id' Dust = Dust; id' _ = undefined

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]