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