Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / lib / config / config.c
blob43df3ae4c7c8eca1fdb4903b748a4f8d95436160
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
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.
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
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"
27 #include <sys/stat.h>
28 #include <sys/mman.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <ctype.h>
33 #define SECTION_B_CHAR '{'
34 #define SECTION_E_CHAR '}'
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
51 struct parser {
52 const char *fb, *fe; /* file limits */
54 int t; /* token limits and type */
55 const char *tb, *te;
57 int fd; /* descriptor for file being parsed */
58 int line; /* line number we are on */
60 struct dm_pool *mem;
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;
73 struct output_line {
74 FILE *fp;
75 struct dm_pool *mem;
76 putline_fn putline;
77 void *putline_baton;
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);
91 static const int sep = '/';
93 #define MAX_INDENT 32
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;\
101 } while(0);
103 static int _tok_match(const char *str, const char *b, const char *e)
105 while (*str && (b != e)) {
106 if (*str++ != *b++)
107 return 0;
110 return !(*str || (b != e));
114 * public interface
116 struct config_tree *create_config_tree(const char *filename, int keep_open)
118 struct cs *c;
119 struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
121 if (!mem) {
122 log_error("Failed to allocate config pool.");
123 return 0;
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;
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;
143 void destroy_config_tree(struct config_tree *cft)
145 struct cs *c = (struct cs *) cft;
147 if (c->dev)
148 dev_close(c->dev);
150 dm_pool_destroy(c->mem);
153 static int _parse_config_file(struct parser *p, struct config_tree *cft)
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;
161 return 1;
164 struct config_tree *create_config_tree_from_string(struct cmd_context *cmd __attribute((unused)),
165 const char *config_settings)
167 struct cs *c;
168 struct config_tree *cft;
169 struct parser *p;
171 if (!(cft = create_config_tree(NULL, 0)))
172 return_NULL;
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;
181 p->mem = c->mem;
182 p->fb = config_settings;
183 p->fe = config_settings + strlen(config_settings);
185 if (!_parse_config_file(p, cft)) {
186 destroy_config_tree(cft);
187 return_NULL;
190 return cft;
193 int override_config_tree_from_string(struct cmd_context *cmd,
194 const char *config_settings)
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;
201 return 0;
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)
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;
215 if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
216 return_0;
217 p->mem = c->mem;
219 /* Only use mmap with regular files */
220 if (!(dev->flags & DEV_REGULAR) || size2)
221 use_mmap = 0;
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;
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;
240 p->fb = buf;
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;
250 p->fe = p->fb + size + size2;
252 if (!_parse_config_file(p, cft))
253 goto_out;
255 r = 1;
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;
268 return r;
271 int read_config_file(struct config_tree *cft)
273 struct cs *c = (struct cs *) cft;
274 struct stat info;
275 int r = 1;
277 if (stat(c->filename, &info)) {
278 log_sys_error("stat", c->filename);
279 c->exists = 0;
280 return 0;
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;
289 c->exists = 1;
291 if (info.st_size == 0) {
292 log_verbose("%s is empty", c->filename);
293 return 1;
296 if (!c->dev) {
297 if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
298 return_0;
300 if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
301 return_0;
304 r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
305 (checksum_fn_t) NULL, 0);
307 if (!c->keep_open) {
308 dev_close(c->dev);
309 c->dev = 0;
312 c->timestamp = info.st_ctime;
314 return r;
317 time_t config_file_timestamp(struct config_tree *cft)
319 struct cs *c = (struct cs *) cft;
321 return c->timestamp;
325 * Return 1 if config files ought to be reloaded
327 int config_file_changed(struct config_tree *cft)
329 struct cs *c = (struct cs *) cft;
330 struct stat info;
332 if (!c->filename)
333 return 0;
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;
344 log_sys_error("stat", c->filename);
345 log_error("Failed to reload configuration files");
346 return 0;
349 if (!S_ISREG(info.st_mode)) {
350 log_error("Configuration file %s is not a regular file",
351 c->filename);
352 goto reload;
355 /* Unchanged? */
356 if (c->timestamp == info.st_ctime)
357 return 0;
359 reload:
360 log_verbose("Detected config file change to %s", c->filename);
361 return 1;
364 static int _line_start(struct output_line *outline)
366 if (!dm_pool_begin_object(outline->mem, 128)) {
367 log_error("dm_pool_begin_object failed for config line");
368 return 0;
371 return 1;
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, ...)
378 char buf[4096];
379 va_list ap;
380 int n;
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;
388 va_end(ap);
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;
395 return 1;
398 #define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
400 static int _line_end(struct output_line *outline)
402 const char *line;
404 if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
405 log_error("dm_pool_grow_object failed for config line");
406 return 0;
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);
419 return 1;
422 static int _write_value(struct output_line *outline, struct config_value *v)
424 char *buf;
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;
433 line_append("\"%s\"", escape_double_quotes(buf, v->v.str));
434 break;
436 case CFG_FLOAT:
437 line_append("%f", v->v.r);
438 break;
440 case CFG_INT:
441 line_append("%" PRId64, v->v.i);
442 break;
444 case CFG_EMPTY_ARRAY:
445 line_append("[]");
446 break;
448 default:
449 log_error("_write_value: Unknown value type: %d", v->type);
453 return 1;
456 static int _write_config(const struct config_node *n, int only_one,
457 struct output_line *outline, int level)
459 char space[MAX_INDENT + 1];
460 int l = (level < MAX_INDENT) ? level : MAX_INDENT;
461 int i;
463 if (!n)
464 return 1;
466 for (i = 0; i < l; i++)
467 space[i] = '\t';
468 space[i] = '\0';
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(", ");
496 line_append("]");
497 } else
498 if (!_write_value(outline, v))
499 return_0;
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;
509 int write_config_node(const struct config_node *cn, putline_fn putline, void *baton)
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;
520 dm_pool_destroy(outline.mem);
521 return 1;
524 int write_config_file(struct config_tree *cft, const char *file,
525 int argc, char **argv)
527 struct config_node *cn;
528 int r = 1;
529 struct output_line outline;
530 outline.fp = NULL;
531 outline.putline = NULL;
533 if (!file)
534 file = "stdout";
535 else if (!(outline.fp = fopen(file, "w"))) {
536 log_sys_error("open", file);
537 return 0;
540 outline.mem = dm_pool_create("config_line", 1024);
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;
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;
554 } else {
555 log_error("Configuration node %s not found", *argv);
556 r = 0;
558 argv++;
561 if (outline.fp && lvm_fclose(outline.fp, file)) {
562 stack;
563 r = 0;
566 dm_pool_destroy(outline.mem);
567 return r;
571 * parser
573 static struct config_node *_file(struct parser *p)
575 struct config_node *root = NULL, *n, *l = NULL;
576 while (p->t != TOK_EOF) {
577 if (!(n = _section(p)))
578 return_0;
580 if (!root)
581 root = n;
582 else
583 l->sib = n;
584 n->parent = root;
585 l = n;
587 return root;
590 static struct config_node *_section(struct parser *p)
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;
597 if (!(root->key = _dup_tok(p)))
598 return_0;
600 match(TOK_IDENTIFIER);
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;
608 if (!root->child)
609 root->child = n;
610 else
611 l->sib = n;
612 n->parent = root;
613 l = n;
615 match(TOK_SECTION_E);
616 } else {
617 match(TOK_EQ);
618 if (!(root->v = _value(p)))
619 return_0;
622 return root;
625 static struct config_value *_value(struct parser *p)
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;
635 if (!h)
636 h = l;
637 else
638 ll->next = l;
639 ll = l;
641 if (p->t == TOK_COMMA)
642 match(TOK_COMMA);
644 match(TOK_ARRAY_E);
646 * Special case for an empty array.
648 if (!h) {
649 if (!(h = _create_value(p->mem)))
650 return NULL;
652 h->type = CFG_EMPTY_ARRAY;
655 } else
656 h = _type(p);
658 return h;
661 static struct config_value *_type(struct parser *p)
663 /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
664 struct config_value *v = _create_value(p->mem);
666 if (!v)
667 return NULL;
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;
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;
682 case TOK_STRING:
683 v->type = CFG_STRING;
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;
692 case TOK_STRING_ESCAPED:
693 v->type = CFG_STRING;
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;
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;
708 return v;
711 static int _match_aux(struct parser *p, int t)
713 if (p->t != t)
714 return 0;
716 _get_token(p, t);
717 return 1;
721 * tokeniser
723 static void _get_token(struct parser *p, int tok_prev)
725 int values_allowed = 0;
727 p->tb = p->te;
728 _eat_space(p);
729 if (p->tb == p->fe || !*p->tb) {
730 p->t = TOK_EOF;
731 return;
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;
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;
747 case SECTION_E_CHAR:
748 p->t = TOK_SECTION_E;
749 p->te++;
750 break;
752 case '[':
753 p->t = TOK_ARRAY_B;
754 p->te++;
755 break;
757 case ']':
758 p->t = TOK_ARRAY_E;
759 p->te++;
760 break;
762 case ',':
763 p->t = TOK_COMMA;
764 p->te++;
765 break;
767 case '=':
768 p->t = TOK_EQ;
769 p->te++;
770 break;
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++;
782 if ((p->te != p->fe) && (*p->te))
783 p->te++;
784 break;
786 case '\'':
787 p->t = TOK_STRING;
788 p->te++;
789 while ((p->te != p->fe) && (*p->te) && (*p->te != '\''))
790 p->te++;
792 if ((p->te != p->fe) && (*p->te))
793 p->te++;
794 break;
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++;
821 break;
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;
835 static void _eat_space(struct parser *p)
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++;
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++;
850 else
851 return;
853 p->tb = p->te;
858 * memory management
860 static struct config_value *_create_value(struct dm_pool *mem)
862 struct config_value *v = dm_pool_alloc(mem, sizeof(*v));
864 if (v)
865 memset(v, 0, sizeof(*v));
867 return v;
870 static struct config_node *_create_node(struct dm_pool *mem)
872 struct config_node *n = dm_pool_alloc(mem, sizeof(*n));
874 if (n)
875 memset(n, 0, sizeof(*n));
877 return n;
880 static char *_dup_tok(struct parser *p)
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;
892 * utility functions
894 static struct config_node *_find_config_node(const struct config_node *cn,
895 const char *path)
897 const char *e;
898 const struct config_node *cn_found = NULL;
900 while (cn) {
901 /* trim any leading slashes */
902 while (*path && (*path == sep))
903 path++;
905 /* find the end of this segment */
906 for (e = path; *e && (*e != sep); e++) ;
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);
921 cn = cn->sib;
924 if (cn_found && *e)
925 cn = cn_found->child;
926 else
927 break; /* don't move into the last node */
929 path = e;
932 return (struct config_node *) cn_found;
935 static struct config_node *_find_first_config_node(const struct config_node *cn1,
936 const struct config_node *cn2,
937 const char *path)
939 struct config_node *cn;
941 if (cn1 && (cn = _find_config_node(cn1, path)))
942 return cn;
944 if (cn2 && (cn = _find_config_node(cn2, path)))
945 return cn;
947 return NULL;
950 struct config_node *find_config_node(const struct config_node *cn,
951 const char *path)
953 return _find_config_node(cn, path);
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)
960 const struct config_node *n = _find_first_config_node(cn1, cn2, path);
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;
968 if (fail)
969 log_very_verbose("%s not found in config: defaulting to %s",
970 path, fail);
971 return fail;
974 const char *find_config_str(const struct config_node *cn,
975 const char *path, const char *fail)
977 return _find_config_str(cn, NULL, path, fail);
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)
984 const struct config_node *n = _find_first_config_node(cn1, cn2, path);
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;
991 log_very_verbose("%s not found in config: defaulting to %" PRId64,
992 path, fail);
993 return fail;
996 int find_config_int(const struct config_node *cn, const char *path, int fail)
998 /* FIXME Add log_error message on overflow */
999 return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
1002 static float _find_config_float(const struct config_node *cn1,
1003 const struct config_node *cn2,
1004 const char *path, float fail)
1006 const struct config_node *n = _find_first_config_node(cn1, cn2, path);
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;
1013 log_very_verbose("%s not found in config: defaulting to %f",
1014 path, fail);
1016 return fail;
1020 float find_config_float(const struct config_node *cn, const char *path,
1021 float fail)
1023 return _find_config_float(cn, NULL, path, fail);
1026 struct config_node *find_config_tree_node(struct cmd_context *cmd,
1027 const char *path)
1029 return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
1032 const char *find_config_tree_str(struct cmd_context *cmd,
1033 const char *path, const char *fail)
1035 return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1038 int find_config_tree_int(struct cmd_context *cmd, const char *path,
1039 int fail)
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);
1045 float find_config_tree_float(struct cmd_context *cmd, const char *path,
1046 float fail)
1048 return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1051 static int _str_in_array(const char *str, const char * const values[])
1053 int i;
1055 for (i = 0; values[i]; i++)
1056 if (!strcasecmp(str, values[i]))
1057 return 1;
1059 return 0;
1062 static int _str_to_bool(const char *str, int fail)
1064 const char * const _true_values[] = { "y", "yes", "on", "true", NULL };
1065 const char * const _false_values[] = { "n", "no", "off", "false", NULL };
1067 if (_str_in_array(str, _true_values))
1068 return 1;
1070 if (_str_in_array(str, _false_values))
1071 return 0;
1073 return fail;
1076 static int _find_config_bool(const struct config_node *cn1,
1077 const struct config_node *cn2,
1078 const char *path, int fail)
1080 const struct config_node *n = _find_first_config_node(cn1, cn2, path);
1081 struct config_value *v;
1083 if (!n)
1084 return fail;
1086 v = n->v;
1088 switch (v->type) {
1089 case CFG_INT:
1090 return v->v.i ? 1 : 0;
1092 case CFG_STRING:
1093 return _str_to_bool(v->v.str, fail);
1096 return fail;
1099 int find_config_bool(const struct config_node *cn, const char *path, int fail)
1101 return _find_config_bool(cn, NULL, path, fail);
1104 int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
1106 return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
1109 int get_config_uint32(const struct config_node *cn, const char *path,
1110 uint32_t *result)
1112 const struct config_node *n;
1114 n = find_config_node(cn, path);
1116 if (!n || !n->v || n->v->type != CFG_INT)
1117 return 0;
1119 *result = n->v->v.i;
1120 return 1;
1123 int get_config_uint64(const struct config_node *cn, const char *path,
1124 uint64_t *result)
1126 const struct config_node *n;
1128 n = find_config_node(cn, path);
1130 if (!n || !n->v || n->v->type != CFG_INT)
1131 return 0;
1133 *result = (uint64_t) n->v->v.i;
1134 return 1;
1137 int get_config_str(const struct config_node *cn, const char *path,
1138 char **result)
1140 const struct config_node *n;
1142 n = find_config_node(cn, path);
1144 if (!n || !n->v || n->v->type != CFG_STRING)
1145 return 0;
1147 *result = n->v->v.str;
1148 return 1;
1151 /* Insert cn2 after cn1 */
1152 static void _insert_config_node(struct config_node **cn1,
1153 struct config_node *cn2)
1155 if (!*cn1) {
1156 *cn1 = cn2;
1157 cn2->sib = NULL;
1158 } else {
1159 cn2->sib = (*cn1)->sib;
1160 (*cn1)->sib = cn2;
1165 * Merge section cn2 into section cn1 (which has the same name)
1166 * overwriting any existing cn1 nodes with matching names.
1168 static void _merge_section(struct config_node *cn1, struct config_node *cn2)
1170 struct config_node *cn, *nextn, *oldn;
1171 struct config_value *cv;
1173 for (cn = cn2->child; cn; cn = nextn) {
1174 nextn = cn->sib;
1176 /* Skip "tags" */
1177 if (!strcmp(cn->key, "tags"))
1178 continue;
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;
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;
1200 /* Replace values */
1201 oldn->v = cn->v;
1205 static int _match_host_tags(struct dm_list *tags, struct config_node *tn)
1207 struct config_value *tv;
1208 const char *str;
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;
1222 return 0;
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)
1229 struct config_node *root = cft->root;
1230 struct config_node *cn, *nextn, *oldn, *tn, *cn2;
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;
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;
1250 if (cn2->sib && !strcmp(cn2->sib->key, "tags")) {
1251 cn2->sib = cn2->sib->sib;
1252 continue;
1255 continue;
1257 _merge_section(oldn, cn);
1260 return 1;
1264 * Convert a token type to the char it represents.
1266 static char _token_type_to_char(int type)
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;
1279 * Returns:
1280 * # of 'type' tokens in 'str'.
1282 static unsigned _count_tokens(const char *str, unsigned len, int type)
1284 char c;
1286 c = _token_type_to_char(type);
1288 return count_chars(str, len, c);
1291 const char *config_parent_name(const struct config_node *n)
1293 return (n->parent ? n->parent->key : "(root)");
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).
1307 * Returns:
1308 * 0 - probably is not a valid config section
1309 * 1 - probably _is_ a valid config section
1311 unsigned maybe_config_section(const char *str, unsigned len)
1313 int begin_count;
1314 int end_count;
1316 begin_count = _count_tokens(str, len, TOK_SECTION_B);
1317 end_count = _count_tokens(str, len, TOK_SECTION_E);
1319 if (begin_count && end_count && (begin_count == end_count))
1320 return 1;
1321 else
1322 return 0;
1325 static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
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;
1339 struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
1340 int siblings)
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;