Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / lvm2 / dist / lib / config / config.c
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 }