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 
_tok_match(const char * str,const char * b,const char * e)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  */
create_config_tree(const char * filename,int keep_open)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 
destroy_config_tree(struct config_tree * cft)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 
_parse_config_file(struct parser * p,struct config_tree * cft)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 
create_config_tree_from_string(struct cmd_context * cmd __attribute ((unused)),const char * config_settings)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 
override_config_tree_from_string(struct cmd_context * cmd,const char * config_settings)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 
read_config_fd(struct config_tree * cft,struct device * dev,off_t offset,size_t size,off_t offset2,size_t size2,checksum_fn_t checksum_fn,uint32_t checksum)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 
read_config_file(struct config_tree * cft)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 
config_file_timestamp(struct config_tree * cft)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  */
config_file_changed(struct config_tree * cft)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 
_line_start(struct output_line * outline)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)));
_line_append(struct output_line * outline,const char * fmt,...)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 
_line_end(struct output_line * outline)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 
_write_value(struct output_line * outline,struct config_value * v)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 
_write_config(const struct config_node * n,int only_one,struct output_line * outline,int level)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 
write_config_node(const struct config_node * cn,putline_fn putline,void * baton)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 
write_config_file(struct config_tree * cft,const char * file,int argc,char ** argv)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  */
_file(struct parser * p)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 
_section(struct parser * p)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 
_value(struct parser * p)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 
_type(struct parser * p)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 
_match_aux(struct parser * p,int t)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  */
_get_token(struct parser * p,int tok_prev)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 
_eat_space(struct parser * p)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  */
_create_value(struct dm_pool * mem)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 
_create_node(struct dm_pool * mem)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 
_dup_tok(struct parser * p)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  */
_find_config_node(const struct config_node * cn,const char * path)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 
_find_first_config_node(const struct config_node * cn1,const struct config_node * cn2,const char * path)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 
find_config_node(const struct config_node * cn,const char * path)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 
_find_config_str(const struct config_node * cn1,const struct config_node * cn2,const char * path,const char * fail)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 
find_config_str(const struct config_node * cn,const char * path,const char * fail)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 
_find_config_int64(const struct config_node * cn1,const struct config_node * cn2,const char * path,int64_t 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)
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 
find_config_int(const struct config_node * cn,const char * path,int fail)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 
_find_config_float(const struct config_node * cn1,const struct config_node * cn2,const char * path,float fail)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 
find_config_float(const struct config_node * cn,const char * path,float fail)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 
find_config_tree_node(struct cmd_context * cmd,const char * path)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 
find_config_tree_str(struct cmd_context * cmd,const char * path,const char * fail)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 
find_config_tree_int(struct cmd_context * cmd,const char * path,int fail)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 
find_config_tree_float(struct cmd_context * cmd,const char * path,float fail)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 
_str_in_array(const char * str,const char * const values[])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 
_str_to_bool(const char * str,int fail)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 
_find_config_bool(const struct config_node * cn1,const struct config_node * cn2,const char * path,int fail)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 
find_config_bool(const struct config_node * cn,const char * path,int fail)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 
find_config_tree_bool(struct cmd_context * cmd,const char * path,int fail)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 
get_config_uint32(const struct config_node * cn,const char * path,uint32_t * result)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 
get_config_uint64(const struct config_node * cn,const char * path,uint64_t * result)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 
get_config_str(const struct config_node * cn,const char * path,char ** result)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 */
_insert_config_node(struct config_node ** cn1,struct config_node * cn2)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  */
_merge_section(struct config_node * cn1,struct config_node * cn2)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 
_match_host_tags(struct dm_list * tags,struct config_node * tn)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 */
merge_config_tree(struct cmd_context * cmd,struct config_tree * cft,struct config_tree * newdata)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  */
_token_type_to_char(int type)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  */
_count_tokens(const char * str,unsigned len,int type)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 
config_parent_name(const struct config_node * n)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  */
maybe_config_section(const char * str,unsigned len)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 
_clone_config_value(struct dm_pool * mem,const struct config_value * v)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 
clone_config_node(struct dm_pool * mem,const struct config_node * cn,int siblings)1339 struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
1340                                               int siblings)
1341 {
1342           if (!cn)
1343                     return NULL;
1344           struct config_node *new = _create_node(mem);
1345           new->key = dm_pool_strdup(mem, cn->key);
1346           new->child = clone_config_node(mem, cn->child, 1);
1347           new->v = _clone_config_value(mem, cn->v);
1348           if (siblings)
1349                     new->sib = clone_config_node(mem, cn->sib, siblings);
1350           else
1351                     new->sib = NULL;
1352           return new;
1353 }
1354