xref: /dragonfly/contrib/lvm2/dist/lib/config/config.c (revision 6ca88057)
1 /*	$NetBSD: config.c,v 1.1.1.2 2009/12/02 00:26:28 haad Exp $	*/
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 
36 enum {
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 
51 struct 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 
63 struct 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 
73 struct output_line {
74 	FILE *fp;
75 	struct dm_pool *mem;
76 	putline_fn putline;
77 	void *putline_baton;
78 };
79 
80 static void _get_token(struct parser *p, int tok_prev);
81 static void _eat_space(struct parser *p);
82 static struct config_node *_file(struct parser *p);
83 static struct config_node *_section(struct parser *p);
84 static struct config_value *_value(struct parser *p);
85 static struct config_value *_type(struct parser *p);
86 static int _match_aux(struct parser *p, int t);
87 static struct config_value *_create_value(struct dm_pool *mem);
88 static struct config_node *_create_node(struct dm_pool *mem);
89 static char *_dup_tok(struct parser *p);
90 
91 static 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 
103 static 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  */
116 struct 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 
143 void 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 
153 static 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 
164 struct 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 
193 int 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 
204 int 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 
271 int 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 
317 time_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  */
327 int 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 
364 static 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 
374 static int _line_append(struct output_line *outline, const char *fmt, ...)
375   __attribute__ ((format(printf, 2, 3)));
376 static 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 
400 static 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 
422 static 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 
456 static 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 
509 int 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 
524 int 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  */
573 static 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 
590 static 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 
625 static 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 
661 static 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 
711 static 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  */
723 static 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 
835 static 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  */
860 static 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 
870 static 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 
880 static 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  */
894 static 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 
935 static 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 
950 struct config_node *find_config_node(const struct config_node *cn,
951 				     const char *path)
952 {
953 	return _find_config_node(cn, path);
954 }
955 
956 static 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 
974 const 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 
980 static 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 
996 int 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 
1002 static 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 
1020 float 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 
1026 struct 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 
1032 const 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 
1038 int 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 
1045 float 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 
1051 static 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 
1062 static 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 
1076 static 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 
1099 int 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 
1104 int 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 
1109 int 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 
1123 int 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 
1137 int 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 */
1152 static 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  */
1168 static 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 
1205 static 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 */
1226 int 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  */
1266 static 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  */
1282 static 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 
1291 const 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  */
1311 unsigned 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 
1325 static 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 
1339 struct 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