1/*	$NetBSD$	*/
2
3/*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6 *
7 * This file is part of LVM2.
8 *
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17
18#include "lib.h"
19#include "config.h"
20#include "crc.h"
21#include "device.h"
22#include "str_list.h"
23#include "toolcontext.h"
24#include "lvm-string.h"
25#include "lvm-file.h"
26
27#include <sys/stat.h>
28#include <sys/mman.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <ctype.h>
32
33#define SECTION_B_CHAR '{'
34#define SECTION_E_CHAR '}'
35
36enum {
37	TOK_INT,
38	TOK_FLOAT,
39	TOK_STRING,		/* Single quotes */
40	TOK_STRING_ESCAPED,	/* Double quotes */
41	TOK_EQ,
42	TOK_SECTION_B,
43	TOK_SECTION_E,
44	TOK_ARRAY_B,
45	TOK_ARRAY_E,
46	TOK_IDENTIFIER,
47	TOK_COMMA,
48	TOK_EOF
49};
50
51struct parser {
52	const char *fb, *fe;		/* file limits */
53
54	int t;			/* token limits and type */
55	const char *tb, *te;
56
57	int fd;			/* descriptor for file being parsed */
58	int line;		/* line number we are on */
59
60	struct dm_pool *mem;
61};
62
63struct cs {
64	struct config_tree cft;
65	struct dm_pool *mem;
66	time_t timestamp;
67	char *filename;
68	int exists;
69	int keep_open;
70	struct device *dev;
71};
72
73struct output_line {
74	FILE *fp;
75	struct dm_pool *mem;
76	putline_fn putline;
77	void *putline_baton;
78};
79
80static void _get_token(struct parser *p, int tok_prev);
81static void _eat_space(struct parser *p);
82static struct config_node *_file(struct parser *p);
83static struct config_node *_section(struct parser *p);
84static struct config_value *_value(struct parser *p);
85static struct config_value *_type(struct parser *p);
86static int _match_aux(struct parser *p, int t);
87static struct config_value *_create_value(struct dm_pool *mem);
88static struct config_node *_create_node(struct dm_pool *mem);
89static char *_dup_tok(struct parser *p);
90
91static const int sep = '/';
92
93#define MAX_INDENT 32
94
95#define match(t) do {\
96   if (!_match_aux(p, (t))) {\
97	log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
98		  p->tb - p->fb + 1, p->line); \
99      return 0;\
100   } \
101} while(0);
102
103static int _tok_match(const char *str, const char *b, const char *e)
104{
105	while (*str && (b != e)) {
106		if (*str++ != *b++)
107			return 0;
108	}
109
110	return !(*str || (b != e));
111}
112
113/*
114 * public interface
115 */
116struct config_tree *create_config_tree(const char *filename, int keep_open)
117{
118	struct cs *c;
119	struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
120
121	if (!mem) {
122		log_error("Failed to allocate config pool.");
123		return 0;
124	}
125
126	if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
127		log_error("Failed to allocate config tree.");
128		dm_pool_destroy(mem);
129		return 0;
130	}
131
132	c->mem = mem;
133	c->cft.root = (struct config_node *) NULL;
134	c->timestamp = 0;
135	c->exists = 0;
136	c->keep_open = keep_open;
137	c->dev = 0;
138	if (filename)
139		c->filename = dm_pool_strdup(c->mem, filename);
140	return &c->cft;
141}
142
143void destroy_config_tree(struct config_tree *cft)
144{
145	struct cs *c = (struct cs *) cft;
146
147	if (c->dev)
148		dev_close(c->dev);
149
150	dm_pool_destroy(c->mem);
151}
152
153static int _parse_config_file(struct parser *p, struct config_tree *cft)
154{
155	p->tb = p->te = p->fb;
156	p->line = 1;
157	_get_token(p, TOK_SECTION_E);
158	if (!(cft->root = _file(p)))
159		return_0;
160
161	return 1;
162}
163
164struct config_tree *create_config_tree_from_string(struct cmd_context *cmd __attribute((unused)),
165						   const char *config_settings)
166{
167	struct cs *c;
168	struct config_tree *cft;
169	struct parser *p;
170
171	if (!(cft = create_config_tree(NULL, 0)))
172		return_NULL;
173
174	c = (struct cs *) cft;
175	if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
176		log_error("Failed to allocate config tree parser.");
177		destroy_config_tree(cft);
178		return NULL;
179	}
180
181	p->mem = c->mem;
182	p->fb = config_settings;
183	p->fe = config_settings + strlen(config_settings);
184
185	if (!_parse_config_file(p, cft)) {
186		destroy_config_tree(cft);
187		return_NULL;
188	}
189
190	return cft;
191}
192
193int override_config_tree_from_string(struct cmd_context *cmd,
194				     const char *config_settings)
195{
196	if (!(cmd->cft_override = create_config_tree_from_string(cmd,config_settings))) {
197		log_error("Failed to set overridden configuration entries.");
198		return 1;
199	}
200
201	return 0;
202}
203
204int read_config_fd(struct config_tree *cft, struct device *dev,
205		   off_t offset, size_t size, off_t offset2, size_t size2,
206		   checksum_fn_t checksum_fn, uint32_t checksum)
207{
208	struct cs *c = (struct cs *) cft;
209	struct parser *p;
210	int r = 0;
211	int use_mmap = 1;
212	off_t mmap_offset = 0;
213	char *buf = NULL;
214
215	if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
216		return_0;
217	p->mem = c->mem;
218
219	/* Only use mmap with regular files */
220	if (!(dev->flags & DEV_REGULAR) || size2)
221		use_mmap = 0;
222
223	if (use_mmap) {
224		mmap_offset = offset % lvm_getpagesize();
225		/* memory map the file */
226		p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
227			     MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
228		if (p->fb == (caddr_t) (-1)) {
229			log_sys_error("mmap", dev_name(dev));
230			goto out;
231		}
232		p->fb = p->fb + mmap_offset;
233	} else {
234		if (!(buf = dm_malloc(size + size2)))
235			return_0;
236		if (!dev_read_circular(dev, (uint64_t) offset, size,
237				       (uint64_t) offset2, size2, buf)) {
238			goto out;
239		}
240		p->fb = buf;
241	}
242
243	if (checksum_fn && checksum !=
244	    (checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
245			 p->fb + size, size2))) {
246		log_error("%s: Checksum error", dev_name(dev));
247		goto out;
248	}
249
250	p->fe = p->fb + size + size2;
251
252	if (!_parse_config_file(p, cft))
253		goto_out;
254
255	r = 1;
256
257      out:
258	if (!use_mmap)
259		dm_free(buf);
260	else {
261		/* unmap the file */
262		if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
263			log_sys_error("munmap", dev_name(dev));
264			r = 0;
265		}
266	}
267
268	return r;
269}
270
271int read_config_file(struct config_tree *cft)
272{
273	struct cs *c = (struct cs *) cft;
274	struct stat info;
275	int r = 1;
276
277	if (stat(c->filename, &info)) {
278		log_sys_error("stat", c->filename);
279		c->exists = 0;
280		return 0;
281	}
282
283	if (!S_ISREG(info.st_mode)) {
284		log_error("%s is not a regular file", c->filename);
285		c->exists = 0;
286		return 0;
287	}
288
289	c->exists = 1;
290
291	if (info.st_size == 0) {
292		log_verbose("%s is empty", c->filename);
293		return 1;
294	}
295
296	if (!c->dev) {
297		if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
298			return_0;
299
300		if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
301			return_0;
302	}
303
304	r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
305			   (checksum_fn_t) NULL, 0);
306
307	if (!c->keep_open) {
308		dev_close(c->dev);
309		c->dev = 0;
310	}
311
312	c->timestamp = info.st_ctime;
313
314	return r;
315}
316
317time_t config_file_timestamp(struct config_tree *cft)
318{
319	struct cs *c = (struct cs *) cft;
320
321	return c->timestamp;
322}
323
324/*
325 * Return 1 if config files ought to be reloaded
326 */
327int config_file_changed(struct config_tree *cft)
328{
329	struct cs *c = (struct cs *) cft;
330	struct stat info;
331
332	if (!c->filename)
333		return 0;
334
335	if (stat(c->filename, &info) == -1) {
336		/* Ignore a deleted config file: still use original data */
337		if (errno == ENOENT) {
338			if (!c->exists)
339				return 0;
340			log_very_verbose("Config file %s has disappeared!",
341					 c->filename);
342			goto reload;
343		}
344		log_sys_error("stat", c->filename);
345		log_error("Failed to reload configuration files");
346		return 0;
347	}
348
349	if (!S_ISREG(info.st_mode)) {
350		log_error("Configuration file %s is not a regular file",
351			  c->filename);
352		goto reload;
353	}
354
355	/* Unchanged? */
356	if (c->timestamp == info.st_ctime)
357		return 0;
358
359      reload:
360	log_verbose("Detected config file change to %s", c->filename);
361	return 1;
362}
363
364static int _line_start(struct output_line *outline)
365{
366	if (!dm_pool_begin_object(outline->mem, 128)) {
367		log_error("dm_pool_begin_object failed for config line");
368		return 0;
369	}
370
371	return 1;
372}
373
374static int _line_append(struct output_line *outline, const char *fmt, ...)
375  __attribute__ ((format(printf, 2, 3)));
376static int _line_append(struct output_line *outline, const char *fmt, ...)
377{
378	char buf[4096];
379	va_list ap;
380	int n;
381
382	va_start(ap, fmt);
383	n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
384	if (n < 0 || n > (int) sizeof buf - 1) {
385		log_error("vsnprintf failed for config line");
386		return 0;
387	}
388	va_end(ap);
389
390	if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
391		log_error("dm_pool_grow_object failed for config line");
392		return 0;
393	}
394
395	return 1;
396}
397
398#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
399
400static int _line_end(struct output_line *outline)
401{
402	const char *line;
403
404	if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
405		log_error("dm_pool_grow_object failed for config line");
406		return 0;
407	}
408
409	line = dm_pool_end_object(outline->mem);
410	if (outline->putline)
411		outline->putline(line, outline->putline_baton);
412	else {
413		if (!outline->fp)
414			log_print("%s", line);
415		else
416			fprintf(outline->fp, "%s\n", line);
417	}
418
419	return 1;
420}
421
422static int _write_value(struct output_line *outline, struct config_value *v)
423{
424	char *buf;
425
426	switch (v->type) {
427	case CFG_STRING:
428		if (!(buf = alloca(escaped_len(v->v.str)))) {
429			log_error("temporary stack allocation for a config "
430				  "string failed");
431			return 0;
432		}
433		line_append("\"%s\"", escape_double_quotes(buf, v->v.str));
434		break;
435
436	case CFG_FLOAT:
437		line_append("%f", v->v.r);
438		break;
439
440	case CFG_INT:
441		line_append("%" PRId64, v->v.i);
442		break;
443
444	case CFG_EMPTY_ARRAY:
445		line_append("[]");
446		break;
447
448	default:
449		log_error("_write_value: Unknown value type: %d", v->type);
450
451	}
452
453	return 1;
454}
455
456static int _write_config(const struct config_node *n, int only_one,
457			 struct output_line *outline, int level)
458{
459	char space[MAX_INDENT + 1];
460	int l = (level < MAX_INDENT) ? level : MAX_INDENT;
461	int i;
462
463	if (!n)
464		return 1;
465
466	for (i = 0; i < l; i++)
467		space[i] = '\t';
468	space[i] = '\0';
469
470	do {
471		if (!_line_start(outline))
472			return_0;
473		line_append("%s%s", space, n->key);
474		if (!n->v) {
475			/* it's a sub section */
476			line_append(" {");
477			if (!_line_end(outline))
478				return_0;
479			_write_config(n->child, 0, outline, level + 1);
480			if (!_line_start(outline))
481				return_0;
482			line_append("%s}", space);
483		} else {
484			/* it's a value */
485			struct config_value *v = n->v;
486			line_append("=");
487			if (v->next) {
488				line_append("[");
489				while (v) {
490					if (!_write_value(outline, v))
491						return_0;
492					v = v->next;
493					if (v)
494						line_append(", ");
495				}
496				line_append("]");
497			} else
498				if (!_write_value(outline, v))
499					return_0;
500		}
501		if (!_line_end(outline))
502			return_0;
503		n = n->sib;
504	} while (n && !only_one);
505	/* FIXME: add error checking */
506	return 1;
507}
508
509int write_config_node(const struct config_node *cn, putline_fn putline, void *baton)
510{
511	struct output_line outline;
512	outline.fp = NULL;
513	outline.mem = dm_pool_create("config_line", 1024);
514	outline.putline = putline;
515	outline.putline_baton = baton;
516	if (!_write_config(cn, 0, &outline, 0)) {
517		dm_pool_destroy(outline.mem);
518		return_0;
519	}
520	dm_pool_destroy(outline.mem);
521	return 1;
522}
523
524int write_config_file(struct config_tree *cft, const char *file,
525		      int argc, char **argv)
526{
527	struct config_node *cn;
528	int r = 1;
529	struct output_line outline;
530	outline.fp = NULL;
531	outline.putline = NULL;
532
533	if (!file)
534		file = "stdout";
535	else if (!(outline.fp = fopen(file, "w"))) {
536		log_sys_error("open", file);
537		return 0;
538	}
539
540	outline.mem = dm_pool_create("config_line", 1024);
541
542	log_verbose("Dumping configuration to %s", file);
543	if (!argc) {
544		if (!_write_config(cft->root, 0, &outline, 0)) {
545			log_error("Failure while writing to %s", file);
546			r = 0;
547		}
548	} else while (argc--) {
549		if ((cn = find_config_node(cft->root, *argv))) {
550			if (!_write_config(cn, 1, &outline, 0)) {
551				log_error("Failure while writing to %s", file);
552				r = 0;
553			}
554		} else {
555			log_error("Configuration node %s not found", *argv);
556			r = 0;
557		}
558		argv++;
559	}
560
561	if (outline.fp && lvm_fclose(outline.fp, file)) {
562		stack;
563		r = 0;
564	}
565
566	dm_pool_destroy(outline.mem);
567	return r;
568}
569
570/*
571 * parser
572 */
573static struct config_node *_file(struct parser *p)
574{
575	struct config_node *root = NULL, *n, *l = NULL;
576	while (p->t != TOK_EOF) {
577		if (!(n = _section(p)))
578			return_0;
579
580		if (!root)
581			root = n;
582		else
583			l->sib = n;
584		n->parent = root;
585		l = n;
586	}
587	return root;
588}
589
590static struct config_node *_section(struct parser *p)
591{
592	/* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
593	struct config_node *root, *n, *l = NULL;
594	if (!(root = _create_node(p->mem)))
595		return_0;
596
597	if (!(root->key = _dup_tok(p)))
598		return_0;
599
600	match(TOK_IDENTIFIER);
601
602	if (p->t == TOK_SECTION_B) {
603		match(TOK_SECTION_B);
604		while (p->t != TOK_SECTION_E) {
605			if (!(n = _section(p)))
606				return_0;
607
608			if (!root->child)
609				root->child = n;
610			else
611				l->sib = n;
612			n->parent = root;
613			l = n;
614		}
615		match(TOK_SECTION_E);
616	} else {
617		match(TOK_EQ);
618		if (!(root->v = _value(p)))
619			return_0;
620	}
621
622	return root;
623}
624
625static struct config_value *_value(struct parser *p)
626{
627	/* '[' TYPE* ']' | TYPE */
628	struct config_value *h = NULL, *l, *ll = NULL;
629	if (p->t == TOK_ARRAY_B) {
630		match(TOK_ARRAY_B);
631		while (p->t != TOK_ARRAY_E) {
632			if (!(l = _type(p)))
633				return_0;
634
635			if (!h)
636				h = l;
637			else
638				ll->next = l;
639			ll = l;
640
641			if (p->t == TOK_COMMA)
642				match(TOK_COMMA);
643		}
644		match(TOK_ARRAY_E);
645		/*
646		 * Special case for an empty array.
647		 */
648		if (!h) {
649			if (!(h = _create_value(p->mem)))
650				return NULL;
651
652			h->type = CFG_EMPTY_ARRAY;
653		}
654
655	} else
656		h = _type(p);
657
658	return h;
659}
660
661static struct config_value *_type(struct parser *p)
662{
663	/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
664	struct config_value *v = _create_value(p->mem);
665
666	if (!v)
667		return NULL;
668
669	switch (p->t) {
670	case TOK_INT:
671		v->type = CFG_INT;
672		v->v.i = strtoll(p->tb, NULL, 0);	/* FIXME: check error */
673		match(TOK_INT);
674		break;
675
676	case TOK_FLOAT:
677		v->type = CFG_FLOAT;
678		v->v.r = strtod(p->tb, NULL);	/* FIXME: check error */
679		match(TOK_FLOAT);
680		break;
681
682	case TOK_STRING:
683		v->type = CFG_STRING;
684
685		p->tb++, p->te--;	/* strip "'s */
686		if (!(v->v.str = _dup_tok(p)))
687			return_0;
688		p->te++;
689		match(TOK_STRING);
690		break;
691
692	case TOK_STRING_ESCAPED:
693		v->type = CFG_STRING;
694
695		p->tb++, p->te--;	/* strip "'s */
696		if (!(v->v.str = _dup_tok(p)))
697			return_0;
698		unescape_double_quotes(v->v.str);
699		p->te++;
700		match(TOK_STRING_ESCAPED);
701		break;
702
703	default:
704		log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
705			  p->tb - p->fb + 1, p->line);
706		return 0;
707	}
708	return v;
709}
710
711static int _match_aux(struct parser *p, int t)
712{
713	if (p->t != t)
714		return 0;
715
716	_get_token(p, t);
717	return 1;
718}
719
720/*
721 * tokeniser
722 */
723static void _get_token(struct parser *p, int tok_prev)
724{
725	int values_allowed = 0;
726
727	p->tb = p->te;
728	_eat_space(p);
729	if (p->tb == p->fe || !*p->tb) {
730		p->t = TOK_EOF;
731		return;
732	}
733
734	/* Should next token be interpreted as value instead of identifier? */
735	if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
736	    tok_prev == TOK_COMMA)
737		values_allowed = 1;
738
739	p->t = TOK_INT;		/* fudge so the fall through for
740				   floats works */
741	switch (*p->te) {
742	case SECTION_B_CHAR:
743		p->t = TOK_SECTION_B;
744		p->te++;
745		break;
746
747	case SECTION_E_CHAR:
748		p->t = TOK_SECTION_E;
749		p->te++;
750		break;
751
752	case '[':
753		p->t = TOK_ARRAY_B;
754		p->te++;
755		break;
756
757	case ']':
758		p->t = TOK_ARRAY_E;
759		p->te++;
760		break;
761
762	case ',':
763		p->t = TOK_COMMA;
764		p->te++;
765		break;
766
767	case '=':
768		p->t = TOK_EQ;
769		p->te++;
770		break;
771
772	case '"':
773		p->t = TOK_STRING_ESCAPED;
774		p->te++;
775		while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
776			if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
777			    *(p->te + 1))
778				p->te++;
779			p->te++;
780		}
781
782		if ((p->te != p->fe) && (*p->te))
783			p->te++;
784		break;
785
786	case '\'':
787		p->t = TOK_STRING;
788		p->te++;
789		while ((p->te != p->fe) && (*p->te) && (*p->te != '\''))
790			p->te++;
791
792		if ((p->te != p->fe) && (*p->te))
793			p->te++;
794		break;
795
796	case '.':
797		p->t = TOK_FLOAT;
798	case '0':
799	case '1':
800	case '2':
801	case '3':
802	case '4':
803	case '5':
804	case '6':
805	case '7':
806	case '8':
807	case '9':
808	case '+':
809	case '-':
810		if (values_allowed) {
811			p->te++;
812			while ((p->te != p->fe) && (*p->te)) {
813				if (*p->te == '.') {
814					if (p->t == TOK_FLOAT)
815						break;
816					p->t = TOK_FLOAT;
817				} else if (!isdigit((int) *p->te))
818					break;
819				p->te++;
820			}
821			break;
822		}
823
824	default:
825		p->t = TOK_IDENTIFIER;
826		while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
827		       (*p->te != '#') && (*p->te != '=') &&
828		       (*p->te != SECTION_B_CHAR) &&
829		       (*p->te != SECTION_E_CHAR))
830			p->te++;
831		break;
832	}
833}
834
835static void _eat_space(struct parser *p)
836{
837	while ((p->tb != p->fe) && (*p->tb)) {
838		if (*p->te == '#')
839			while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
840				p->te++;
841
842		else if (isspace(*p->te)) {
843			while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
844				if (*p->te == '\n')
845					p->line++;
846				p->te++;
847			}
848		}
849
850		else
851			return;
852
853		p->tb = p->te;
854	}
855}
856
857/*
858 * memory management
859 */
860static struct config_value *_create_value(struct dm_pool *mem)
861{
862	struct config_value *v = dm_pool_alloc(mem, sizeof(*v));
863
864	if (v)
865		memset(v, 0, sizeof(*v));
866
867	return v;
868}
869
870static struct config_node *_create_node(struct dm_pool *mem)
871{
872	struct config_node *n = dm_pool_alloc(mem, sizeof(*n));
873
874	if (n)
875		memset(n, 0, sizeof(*n));
876
877	return n;
878}
879
880static char *_dup_tok(struct parser *p)
881{
882	size_t len = p->te - p->tb;
883	char *str = dm_pool_alloc(p->mem, len + 1);
884	if (!str)
885		return_0;
886	strncpy(str, p->tb, len);
887	str[len] = '\0';
888	return str;
889}
890
891/*
892 * utility functions
893 */
894static struct config_node *_find_config_node(const struct config_node *cn,
895					     const char *path)
896{
897	const char *e;
898	const struct config_node *cn_found = NULL;
899
900	while (cn) {
901		/* trim any leading slashes */
902		while (*path && (*path == sep))
903			path++;
904
905		/* find the end of this segment */
906		for (e = path; *e && (*e != sep); e++) ;
907
908		/* hunt for the node */
909		cn_found = NULL;
910		while (cn) {
911			if (_tok_match(cn->key, path, e)) {
912				/* Inefficient */
913				if (!cn_found)
914					cn_found = cn;
915				else
916					log_error("WARNING: Ignoring duplicate"
917						  " config node: %s ("
918						  "seeking %s)", cn->key, path);
919			}
920
921			cn = cn->sib;
922		}
923
924		if (cn_found && *e)
925			cn = cn_found->child;
926		else
927			break;	/* don't move into the last node */
928
929		path = e;
930	}
931
932	return (struct config_node *) cn_found;
933}
934
935static struct config_node *_find_first_config_node(const struct config_node *cn1,
936						   const struct config_node *cn2,
937						   const char *path)
938{
939	struct config_node *cn;
940
941	if (cn1 && (cn = _find_config_node(cn1, path)))
942		return cn;
943
944	if (cn2 && (cn = _find_config_node(cn2, path)))
945		return cn;
946
947	return NULL;
948}
949
950struct config_node *find_config_node(const struct config_node *cn,
951				     const char *path)
952{
953	return _find_config_node(cn, path);
954}
955
956static const char *_find_config_str(const struct config_node *cn1,
957				    const struct config_node *cn2,
958				    const char *path, const char *fail)
959{
960	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
961
962	/* Empty strings are ignored */
963	if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
964		log_very_verbose("Setting %s to %s", path, n->v->v.str);
965		return n->v->v.str;
966	}
967
968	if (fail)
969		log_very_verbose("%s not found in config: defaulting to %s",
970				 path, fail);
971	return fail;
972}
973
974const char *find_config_str(const struct config_node *cn,
975			    const char *path, const char *fail)
976{
977	return _find_config_str(cn, NULL, path, fail);
978}
979
980static int64_t _find_config_int64(const struct config_node *cn1,
981				  const struct config_node *cn2,
982				  const char *path, int64_t fail)
983{
984	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
985
986	if (n && n->v && n->v->type == CFG_INT) {
987		log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
988		return n->v->v.i;
989	}
990
991	log_very_verbose("%s not found in config: defaulting to %" PRId64,
992			 path, fail);
993	return fail;
994}
995
996int find_config_int(const struct config_node *cn, const char *path, int fail)
997{
998	/* FIXME Add log_error message on overflow */
999	return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
1000}
1001
1002static float _find_config_float(const struct config_node *cn1,
1003				const struct config_node *cn2,
1004				const char *path, float fail)
1005{
1006	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
1007
1008	if (n && n->v && n->v->type == CFG_FLOAT) {
1009		log_very_verbose("Setting %s to %f", path, n->v->v.r);
1010		return n->v->v.r;
1011	}
1012
1013	log_very_verbose("%s not found in config: defaulting to %f",
1014			 path, fail);
1015
1016	return fail;
1017
1018}
1019
1020float find_config_float(const struct config_node *cn, const char *path,
1021			float fail)
1022{
1023	return _find_config_float(cn, NULL, path, fail);
1024}
1025
1026struct config_node *find_config_tree_node(struct cmd_context *cmd,
1027					  const char *path)
1028{
1029	return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
1030}
1031
1032const char *find_config_tree_str(struct cmd_context *cmd,
1033				 const char *path, const char *fail)
1034{
1035	return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1036}
1037
1038int find_config_tree_int(struct cmd_context *cmd, const char *path,
1039			 int fail)
1040{
1041	/* FIXME Add log_error message on overflow */
1042	return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
1043}
1044
1045float find_config_tree_float(struct cmd_context *cmd, const char *path,
1046			     float fail)
1047{
1048	return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1049}
1050
1051static int _str_in_array(const char *str, const char * const values[])
1052{
1053	int i;
1054
1055	for (i = 0; values[i]; i++)
1056		if (!strcasecmp(str, values[i]))
1057			return 1;
1058
1059	return 0;
1060}
1061
1062static int _str_to_bool(const char *str, int fail)
1063{
1064	const char * const _true_values[]  = { "y", "yes", "on", "true", NULL };
1065	const char * const _false_values[] = { "n", "no", "off", "false", NULL };
1066
1067	if (_str_in_array(str, _true_values))
1068		return 1;
1069
1070	if (_str_in_array(str, _false_values))
1071		return 0;
1072
1073	return fail;
1074}
1075
1076static int _find_config_bool(const struct config_node *cn1,
1077			     const struct config_node *cn2,
1078			     const char *path, int fail)
1079{
1080	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
1081	struct config_value *v;
1082
1083	if (!n)
1084		return fail;
1085
1086	v = n->v;
1087
1088	switch (v->type) {
1089	case CFG_INT:
1090		return v->v.i ? 1 : 0;
1091
1092	case CFG_STRING:
1093		return _str_to_bool(v->v.str, fail);
1094	}
1095
1096	return fail;
1097}
1098
1099int find_config_bool(const struct config_node *cn, const char *path, int fail)
1100{
1101	return _find_config_bool(cn, NULL, path, fail);
1102}
1103
1104int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
1105{
1106	return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1107}
1108
1109int get_config_uint32(const struct config_node *cn, const char *path,
1110		      uint32_t *result)
1111{
1112	const struct config_node *n;
1113
1114	n = find_config_node(cn, path);
1115
1116	if (!n || !n->v || n->v->type != CFG_INT)
1117		return 0;
1118
1119	*result = n->v->v.i;
1120	return 1;
1121}
1122
1123int get_config_uint64(const struct config_node *cn, const char *path,
1124		      uint64_t *result)
1125{
1126	const struct config_node *n;
1127
1128	n = find_config_node(cn, path);
1129
1130	if (!n || !n->v || n->v->type != CFG_INT)
1131		return 0;
1132
1133	*result = (uint64_t) n->v->v.i;
1134	return 1;
1135}
1136
1137int get_config_str(const struct config_node *cn, const char *path,
1138		   char **result)
1139{
1140	const struct config_node *n;
1141
1142	n = find_config_node(cn, path);
1143
1144	if (!n || !n->v || n->v->type != CFG_STRING)
1145		return 0;
1146
1147	*result = n->v->v.str;
1148	return 1;
1149}
1150
1151/* Insert cn2 after cn1 */
1152static void _insert_config_node(struct config_node **cn1,
1153				struct config_node *cn2)
1154{
1155	if (!*cn1) {
1156		*cn1 = cn2;
1157		cn2->sib = NULL;
1158	} else {
1159		cn2->sib = (*cn1)->sib;
1160		(*cn1)->sib = cn2;
1161	}
1162}
1163
1164/*
1165 * Merge section cn2 into section cn1 (which has the same name)
1166 * overwriting any existing cn1 nodes with matching names.
1167 */
1168static void _merge_section(struct config_node *cn1, struct config_node *cn2)
1169{
1170	struct config_node *cn, *nextn, *oldn;
1171	struct config_value *cv;
1172
1173	for (cn = cn2->child; cn; cn = nextn) {
1174		nextn = cn->sib;
1175
1176		/* Skip "tags" */
1177		if (!strcmp(cn->key, "tags"))
1178			continue;
1179
1180		/* Subsection? */
1181		if (!cn->v)
1182			/* Ignore - we don't have any of these yet */
1183			continue;
1184		/* Not already present? */
1185		if (!(oldn = find_config_node(cn1->child, cn->key))) {
1186			_insert_config_node(&cn1->child, cn);
1187			continue;
1188		}
1189		/* Merge certain value lists */
1190		if ((!strcmp(cn1->key, "activation") &&
1191		     !strcmp(cn->key, "volume_list")) ||
1192		    (!strcmp(cn1->key, "devices") &&
1193		     (!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) {
1194			cv = cn->v;
1195			while (cv->next)
1196				cv = cv->next;
1197			cv->next = oldn->v;
1198		}
1199
1200		/* Replace values */
1201		oldn->v = cn->v;
1202	}
1203}
1204
1205static int _match_host_tags(struct dm_list *tags, struct config_node *tn)
1206{
1207	struct config_value *tv;
1208	const char *str;
1209
1210	for (tv = tn->v; tv; tv = tv->next) {
1211		if (tv->type != CFG_STRING)
1212			continue;
1213		str = tv->v.str;
1214		if (*str == '@')
1215			str++;
1216		if (!*str)
1217			continue;
1218		if (str_list_match_item(tags, str))
1219			return 1;
1220	}
1221
1222	return 0;
1223}
1224
1225/* Destructively merge a new config tree into an existing one */
1226int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
1227		      struct config_tree *newdata)
1228{
1229	struct config_node *root = cft->root;
1230	struct config_node *cn, *nextn, *oldn, *tn, *cn2;
1231
1232	for (cn = newdata->root; cn; cn = nextn) {
1233		nextn = cn->sib;
1234		/* Ignore tags section */
1235		if (!strcmp(cn->key, "tags"))
1236			continue;
1237		/* If there's a tags node, skip if host tags don't match */
1238		if ((tn = find_config_node(cn->child, "tags"))) {
1239			if (!_match_host_tags(&cmd->tags, tn))
1240				continue;
1241		}
1242		if (!(oldn = find_config_node(root, cn->key))) {
1243			_insert_config_node(&cft->root, cn);
1244			/* Remove any "tags" nodes */
1245			for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
1246				if (!strcmp(cn2->key, "tags")) {
1247					cn->child = cn2->sib;
1248					continue;
1249				}
1250				if (cn2->sib && !strcmp(cn2->sib->key, "tags")) {
1251					cn2->sib = cn2->sib->sib;
1252					continue;
1253				}
1254			}
1255			continue;
1256		}
1257		_merge_section(oldn, cn);
1258	}
1259
1260	return 1;
1261}
1262
1263/*
1264 * Convert a token type to the char it represents.
1265 */
1266static char _token_type_to_char(int type)
1267{
1268	switch (type) {
1269		case TOK_SECTION_B:
1270			return SECTION_B_CHAR;
1271		case TOK_SECTION_E:
1272			return SECTION_E_CHAR;
1273		default:
1274			return 0;
1275	}
1276}
1277
1278/*
1279 * Returns:
1280 *  # of 'type' tokens in 'str'.
1281 */
1282static unsigned _count_tokens(const char *str, unsigned len, int type)
1283{
1284	char c;
1285
1286	c = _token_type_to_char(type);
1287
1288	return count_chars(str, len, c);
1289}
1290
1291const char *config_parent_name(const struct config_node *n)
1292{
1293	return (n->parent ? n->parent->key : "(root)");
1294}
1295/*
1296 * Heuristic function to make a quick guess as to whether a text
1297 * region probably contains a valid config "section".  (Useful for
1298 * scanning areas of the disk for old metadata.)
1299 * Config sections contain various tokens, may contain other sections
1300 * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
1301 * end (type 'TOK_SECTION_E') tokens.  As a quick heuristic, we just
1302 * count the number of begin and end tokens, and see if they are
1303 * non-zero and the counts match.
1304 * Full validation of the section should be done with another function
1305 * (for example, read_config_fd).
1306 *
1307 * Returns:
1308 *  0 - probably is not a valid config section
1309 *  1 - probably _is_ a valid config section
1310 */
1311unsigned maybe_config_section(const char *str, unsigned len)
1312{
1313	int begin_count;
1314	int end_count;
1315
1316	begin_count = _count_tokens(str, len, TOK_SECTION_B);
1317	end_count = _count_tokens(str, len, TOK_SECTION_E);
1318
1319	if (begin_count && end_count && (begin_count == end_count))
1320		return 1;
1321	else
1322		return 0;
1323}
1324
1325static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
1326{
1327	if (!v)
1328		return NULL;
1329	struct config_value *new = _create_value(mem);
1330	new->type = v->type;
1331	if (v->type == CFG_STRING)
1332		new->v.str = dm_pool_strdup(mem, v->v.str);
1333	else
1334		new->v = v->v;
1335	new->next = _clone_config_value(mem, v->next);
1336	return new;
1337}
1338
1339struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
1340				      int siblings)
1341{
1342	if (!cn)
1343		return NULL;
1344	struct config_node *new = _create_node(mem);
1345	new->key = dm_pool_strdup(mem, cn->key);
1346	new->child = clone_config_node(mem, cn->child, 1);
1347	new->v = _clone_config_value(mem, cn->v);
1348	if (siblings)
1349		new->sib = clone_config_node(mem, cn->sib, siblings);
1350	else
1351		new->sib = NULL;
1352	return new;
1353}
1354