]> sourceware.org Git - lvm2.git/blame - libdm/libdm-config.c
Fix error message when pvmove LV activation fails with name already in use.
[lvm2.git] / libdm / libdm-config.c
CommitLineData
e59e2f7c
PR
1/*
2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
4 *
5 * This file is part of LVM2.
6 *
7 * This copyrighted material is made available to anyone wishing to use,
8 * modify, copy, or redistribute it subject to the terms and conditions
9 * of the GNU Lesser General Public License v.2.1.
10 *
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, write to the Free Software Foundation,
13 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 */
15
16#include "dmlib.h"
17
18#include <sys/stat.h>
19#include <sys/mman.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <ctype.h>
23
24#define SECTION_B_CHAR '{'
25#define SECTION_E_CHAR '}'
26
27enum {
28 TOK_INT,
29 TOK_FLOAT,
30 TOK_STRING, /* Single quotes */
31 TOK_STRING_ESCAPED, /* Double quotes */
32 TOK_EQ,
33 TOK_SECTION_B,
34 TOK_SECTION_E,
35 TOK_ARRAY_B,
36 TOK_ARRAY_E,
37 TOK_IDENTIFIER,
38 TOK_COMMA,
39 TOK_EOF
40};
41
42struct parser {
43 const char *fb, *fe; /* file limits */
44
45 int t; /* token limits and type */
46 const char *tb, *te;
47
48 int line; /* line number we are on */
49
50 struct dm_pool *mem;
51};
52
e59e2f7c 53struct output_line {
e59e2f7c
PR
54 struct dm_pool *mem;
55 dm_putline_fn putline;
56 void *putline_baton;
57};
58
59static void _get_token(struct parser *p, int tok_prev);
60static void _eat_space(struct parser *p);
61static struct dm_config_node *_file(struct parser *p);
62static struct dm_config_node *_section(struct parser *p);
63static struct dm_config_value *_value(struct parser *p);
64static struct dm_config_value *_type(struct parser *p);
65static int _match_aux(struct parser *p, int t);
66static struct dm_config_value *_create_value(struct dm_pool *mem);
67static struct dm_config_node *_create_node(struct dm_pool *mem);
68static char *_dup_tok(struct parser *p);
69
70static const int sep = '/';
71
72#define MAX_INDENT 32
73
74#define match(t) do {\
75 if (!_match_aux(p, (t))) {\
76 log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
77 p->tb - p->fb + 1, p->line); \
78 return 0;\
79 } \
80} while(0);
81
82static int _tok_match(const char *str, const char *b, const char *e)
83{
84 while (*str && (b != e)) {
85 if (*str++ != *b++)
86 return 0;
87 }
88
89 return !(*str || (b != e));
90}
91
e38b557a 92struct dm_config_tree *dm_config_create(void)
e59e2f7c 93{
845b1df6 94 struct dm_config_tree *cft;
e59e2f7c
PR
95 struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
96
97 if (!mem) {
98 log_error("Failed to allocate config pool.");
99 return 0;
100 }
101
845b1df6 102 if (!(cft = dm_pool_zalloc(mem, sizeof(*cft)))) {
e59e2f7c
PR
103 log_error("Failed to allocate config tree.");
104 dm_pool_destroy(mem);
105 return 0;
106 }
845b1df6
PR
107 cft->root = NULL;
108 cft->cascade = NULL;
109 cft->custom = NULL;
110 cft->mem = mem;
111 return cft;
e59e2f7c
PR
112}
113
114void dm_config_set_custom(struct dm_config_tree *cft, void *custom)
115{
845b1df6 116 cft->custom = custom;
e59e2f7c
PR
117}
118
119void *dm_config_get_custom(struct dm_config_tree *cft)
120{
845b1df6 121 return cft->custom;
e59e2f7c
PR
122}
123
124void dm_config_destroy(struct dm_config_tree *cft)
125{
845b1df6 126 dm_pool_destroy(cft->mem);
e59e2f7c
PR
127}
128
c82c2beb
AK
129/*
130 * If there's a cascaded dm_config_tree, remove and return it, otherwise
131 * return NULL.
132 */
133struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft)
134{
5a6ae6f5 135 struct dm_config_tree *second_cft;
c82c2beb 136
5a6ae6f5
ZK
137 if (!cft)
138 return NULL;
139
140 second_cft = cft->cascade;
c82c2beb
AK
141 cft->cascade = NULL;
142
143 return second_cft;
144}
145
146/*
147 * When searching, first_cft is checked before second_cft.
148 */
149struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_cft)
150{
151 first_cft->cascade = second_cft;
152
153 return first_cft;
154}
155
e59e2f7c
PR
156int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end)
157{
158 /* TODO? if (start == end) return 1; */
159
e59e2f7c 160 struct parser *p;
845b1df6 161 if (!(p = dm_pool_alloc(cft->mem, sizeof(*p))))
e59e2f7c
PR
162 return_0;
163
845b1df6 164 p->mem = cft->mem;
e59e2f7c
PR
165 p->fb = start;
166 p->fe = end;
167 p->tb = p->te = p->fb;
168 p->line = 1;
169
170 _get_token(p, TOK_SECTION_E);
171 if (!(cft->root = _file(p)))
172 return_0;
173
174 return 1;
175}
176
177struct dm_config_tree *dm_config_from_string(const char *config_settings)
178{
179 struct dm_config_tree *cft;
180
845b1df6 181 if (!(cft = dm_config_create()))
e59e2f7c
PR
182 return_NULL;
183
184 if (!dm_config_parse(cft, config_settings, config_settings + strlen(config_settings))) {
185 dm_config_destroy(cft);
186 return_NULL;
187 }
188
189 return cft;
190}
191
e59e2f7c
PR
192static int _line_start(struct output_line *outline)
193{
194 if (!dm_pool_begin_object(outline->mem, 128)) {
195 log_error("dm_pool_begin_object failed for config line");
196 return 0;
197 }
198
199 return 1;
200}
201
347e1afd 202__attribute__ ((format(printf, 2, 3)))
e59e2f7c
PR
203static int _line_append(struct output_line *outline, const char *fmt, ...)
204{
205 char buf[4096];
206 va_list ap;
207 int n;
208
209 va_start(ap, fmt);
210 n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
211 va_end(ap);
212
213 if (n < 0 || n > (int) sizeof buf - 1) {
214 log_error("vsnprintf failed for config line");
215 return 0;
216 }
217
218 if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
219 log_error("dm_pool_grow_object failed for config line");
220 return 0;
221 }
222
223 return 1;
224}
225
226#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
227
228static int _line_end(struct output_line *outline)
229{
230 const char *line;
231
232 if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
233 log_error("dm_pool_grow_object failed for config line");
234 return 0;
235 }
236
237 line = dm_pool_end_object(outline->mem);
11e52025
PR
238
239 if (!outline->putline)
240 return 0;
241
242 outline->putline(line, outline->putline_baton);
e59e2f7c
PR
243
244 return 1;
245}
246
247static int _write_value(struct output_line *outline, const struct dm_config_value *v)
248{
249 char *buf;
250
251 switch (v->type) {
252 case DM_CFG_STRING:
253 if (!(buf = alloca(dm_escaped_len(v->v.str)))) {
254 log_error("temporary stack allocation for a config "
255 "string failed");
256 return 0;
257 }
258 line_append("\"%s\"", dm_escape_double_quotes(buf, v->v.str));
259 break;
260
261 case DM_CFG_FLOAT:
fe8f5dbe 262 line_append("%f", v->v.f);
e59e2f7c
PR
263 break;
264
265 case DM_CFG_INT:
266 line_append("%" PRId64, v->v.i);
267 break;
268
269 case DM_CFG_EMPTY_ARRAY:
270 line_append("[]");
271 break;
272
273 default:
274 log_error("_write_value: Unknown value type: %d", v->type);
275
276 }
277
278 return 1;
279}
280
281static int _write_config(const struct dm_config_node *n, int only_one,
282 struct output_line *outline, int level)
283{
284 char space[MAX_INDENT + 1];
285 int l = (level < MAX_INDENT) ? level : MAX_INDENT;
286 int i;
287
288 if (!n)
289 return 1;
290
291 for (i = 0; i < l; i++)
292 space[i] = '\t';
293 space[i] = '\0';
294
295 do {
296 if (!_line_start(outline))
297 return_0;
298 line_append("%s%s", space, n->key);
299 if (!n->v) {
300 /* it's a sub section */
301 line_append(" {");
302 if (!_line_end(outline))
303 return_0;
304 _write_config(n->child, 0, outline, level + 1);
305 if (!_line_start(outline))
306 return_0;
307 line_append("%s}", space);
308 } else {
309 /* it's a value */
310 const struct dm_config_value *v = n->v;
311 line_append("=");
312 if (v->next) {
313 line_append("[");
314 while (v && v->type != DM_CFG_EMPTY_ARRAY) {
315 if (!_write_value(outline, v))
316 return_0;
317 v = v->next;
318 if (v && v->type != DM_CFG_EMPTY_ARRAY)
319 line_append(", ");
320 }
321 line_append("]");
322 } else
323 if (!_write_value(outline, v))
324 return_0;
325 }
326 if (!_line_end(outline))
327 return_0;
328 n = n->sib;
329 } while (n && !only_one);
330 /* FIXME: add error checking */
331 return 1;
332}
333
334int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton)
335{
336 struct output_line outline;
e59e2f7c
PR
337 if (!(outline.mem = dm_pool_create("config_line", 1024)))
338 return_0;
339 outline.putline = putline;
340 outline.putline_baton = baton;
341 if (!_write_config(cn, 0, &outline, 0)) {
342 dm_pool_destroy(outline.mem);
343 return_0;
344 }
345 dm_pool_destroy(outline.mem);
346 return 1;
347}
348
e59e2f7c
PR
349
350/*
351 * parser
352 */
353static struct dm_config_node *_file(struct parser *p)
354{
355 struct dm_config_node *root = NULL, *n, *l = NULL;
356 while (p->t != TOK_EOF) {
357 if (!(n = _section(p)))
f45106b7 358 return_NULL;
e59e2f7c
PR
359
360 if (!root)
361 root = n;
362 else
363 l->sib = n;
364 n->parent = root;
365 l = n;
366 }
367 return root;
368}
369
370static struct dm_config_node *_section(struct parser *p)
371{
372 /* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
373 struct dm_config_node *root, *n, *l = NULL;
d2c25f02
ZK
374 if (!(root = _create_node(p->mem))) {
375 log_error("Failed to allocate section node");
376 return NULL;
377 }
e59e2f7c
PR
378
379 if (!(root->key = _dup_tok(p)))
f45106b7 380 return_NULL;
e59e2f7c
PR
381
382 match(TOK_IDENTIFIER);
383
384 if (p->t == TOK_SECTION_B) {
385 match(TOK_SECTION_B);
386 while (p->t != TOK_SECTION_E) {
387 if (!(n = _section(p)))
f45106b7 388 return_NULL;
e59e2f7c 389
5ce39c67 390 if (!l)
e59e2f7c
PR
391 root->child = n;
392 else
393 l->sib = n;
394 n->parent = root;
395 l = n;
396 }
397 match(TOK_SECTION_E);
398 } else {
399 match(TOK_EQ);
400 if (!(root->v = _value(p)))
f45106b7 401 return_NULL;
e59e2f7c
PR
402 }
403
404 return root;
405}
406
407static struct dm_config_value *_value(struct parser *p)
408{
409 /* '[' TYPE* ']' | TYPE */
410 struct dm_config_value *h = NULL, *l, *ll = NULL;
411 if (p->t == TOK_ARRAY_B) {
412 match(TOK_ARRAY_B);
413 while (p->t != TOK_ARRAY_E) {
414 if (!(l = _type(p)))
f45106b7 415 return_NULL;
e59e2f7c
PR
416
417 if (!h)
418 h = l;
419 else
420 ll->next = l;
421 ll = l;
422
423 if (p->t == TOK_COMMA)
424 match(TOK_COMMA);
425 }
426 match(TOK_ARRAY_E);
427 /*
428 * Special case for an empty array.
429 */
430 if (!h) {
d2c25f02
ZK
431 if (!(h = _create_value(p->mem))) {
432 log_error("Failed to allocate value");
433 return NULL;
434 }
e59e2f7c
PR
435
436 h->type = DM_CFG_EMPTY_ARRAY;
437 }
438
439 } else
60444f8b
ZK
440 if (!(h = _type(p)))
441 return_NULL;
e59e2f7c
PR
442
443 return h;
444}
445
446static struct dm_config_value *_type(struct parser *p)
447{
448 /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
449 struct dm_config_value *v = _create_value(p->mem);
450 char *str;
451
d2c25f02
ZK
452 if (!v) {
453 log_error("Failed to allocate type value");
e59e2f7c 454 return NULL;
d2c25f02 455 }
e59e2f7c
PR
456
457 switch (p->t) {
458 case TOK_INT:
459 v->type = DM_CFG_INT;
460 v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
461 match(TOK_INT);
462 break;
463
464 case TOK_FLOAT:
465 v->type = DM_CFG_FLOAT;
fe8f5dbe 466 v->v.f = strtod(p->tb, NULL); /* FIXME: check error */
e59e2f7c
PR
467 match(TOK_FLOAT);
468 break;
469
470 case TOK_STRING:
471 v->type = DM_CFG_STRING;
472
473 p->tb++, p->te--; /* strip "'s */
474 if (!(v->v.str = _dup_tok(p)))
f45106b7 475 return_NULL;
e59e2f7c
PR
476 p->te++;
477 match(TOK_STRING);
478 break;
479
480 case TOK_STRING_ESCAPED:
481 v->type = DM_CFG_STRING;
482
483 p->tb++, p->te--; /* strip "'s */
484 if (!(str = _dup_tok(p)))
f45106b7 485 return_NULL;
e59e2f7c
PR
486 dm_unescape_double_quotes(str);
487 v->v.str = str;
488 p->te++;
489 match(TOK_STRING_ESCAPED);
490 break;
491
492 default:
493 log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
494 p->tb - p->fb + 1, p->line);
f45106b7 495 return NULL;
e59e2f7c
PR
496 }
497 return v;
498}
499
500static int _match_aux(struct parser *p, int t)
501{
502 if (p->t != t)
503 return 0;
504
505 _get_token(p, t);
506 return 1;
507}
508
509/*
510 * tokeniser
511 */
512static void _get_token(struct parser *p, int tok_prev)
513{
514 int values_allowed = 0;
515
516 const char *te;
517
518 p->tb = p->te;
519 _eat_space(p);
520 if (p->tb == p->fe || !*p->tb) {
521 p->t = TOK_EOF;
522 return;
523 }
524
525 /* Should next token be interpreted as value instead of identifier? */
526 if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
527 tok_prev == TOK_COMMA)
528 values_allowed = 1;
529
530 p->t = TOK_INT; /* fudge so the fall through for
531 floats works */
532
533 te = p->te;
534 switch (*te) {
535 case SECTION_B_CHAR:
536 p->t = TOK_SECTION_B;
537 te++;
538 break;
539
540 case SECTION_E_CHAR:
541 p->t = TOK_SECTION_E;
542 te++;
543 break;
544
545 case '[':
546 p->t = TOK_ARRAY_B;
547 te++;
548 break;
549
550 case ']':
551 p->t = TOK_ARRAY_E;
552 te++;
553 break;
554
555 case ',':
556 p->t = TOK_COMMA;
557 te++;
558 break;
559
560 case '=':
561 p->t = TOK_EQ;
562 te++;
563 break;
564
565 case '"':
566 p->t = TOK_STRING_ESCAPED;
567 te++;
568 while ((te != p->fe) && (*te) && (*te != '"')) {
569 if ((*te == '\\') && (te + 1 != p->fe) &&
570 *(te + 1))
571 te++;
572 te++;
573 }
574
575 if ((te != p->fe) && (*te))
576 te++;
577 break;
578
579 case '\'':
580 p->t = TOK_STRING;
581 te++;
582 while ((te != p->fe) && (*te) && (*te != '\''))
583 te++;
584
585 if ((te != p->fe) && (*te))
586 te++;
587 break;
588
589 case '.':
590 p->t = TOK_FLOAT;
591 /* Fall through */
592 case '0':
593 case '1':
594 case '2':
595 case '3':
596 case '4':
597 case '5':
598 case '6':
599 case '7':
600 case '8':
601 case '9':
602 case '+':
603 case '-':
604 if (values_allowed) {
605 while (++te != p->fe) {
606 if (!isdigit((int) *te)) {
607 if (*te == '.') {
608 if (p->t != TOK_FLOAT) {
609 p->t = TOK_FLOAT;
610 continue;
611 }
612 }
613 break;
614 }
615 }
616 break;
617 }
618 /* fall through */
619
620 default:
621 p->t = TOK_IDENTIFIER;
622 while ((te != p->fe) && (*te) && !isspace(*te) &&
623 (*te != '#') && (*te != '=') &&
624 (*te != SECTION_B_CHAR) &&
625 (*te != SECTION_E_CHAR))
626 te++;
627 break;
628 }
629
630 p->te = te;
631}
632
633static void _eat_space(struct parser *p)
634{
635 while (p->tb != p->fe) {
636 if (*p->te == '#')
637 while ((p->te != p->fe) && (*p->te != '\n') && (*p->te))
638 ++p->te;
639
640 else if (!isspace(*p->te))
641 break;
642
643 while ((p->te != p->fe) && isspace(*p->te)) {
644 if (*p->te == '\n')
645 ++p->line;
646 ++p->te;
647 }
648
649 p->tb = p->te;
650 }
651}
652
653/*
654 * memory management
655 */
656static struct dm_config_value *_create_value(struct dm_pool *mem)
657{
658 return dm_pool_zalloc(mem, sizeof(struct dm_config_value));
659}
660
661static struct dm_config_node *_create_node(struct dm_pool *mem)
662{
663 return dm_pool_zalloc(mem, sizeof(struct dm_config_node));
664}
665
666static char *_dup_tok(struct parser *p)
667{
668 size_t len = p->te - p->tb;
669 char *str = dm_pool_alloc(p->mem, len + 1);
670 if (!str) {
671 log_error("Failed to duplicate token.");
672 return 0;
673 }
674 memcpy(str, p->tb, len);
675 str[len] = '\0';
676 return str;
677}
678
679/*
fe8f5dbe
AK
680 * Utility functions
681 */
682
683/*
684 * node_lookup_fn is either:
685 * _find_config_node to perform a lookup starting from a given config_node
686 * in a config_tree;
687 * or
688 * _find_first_config_node to find the first config_node in a set of
689 * cascaded trees.
e59e2f7c 690 */
fe8f5dbe
AK
691typedef const struct dm_config_node *node_lookup_fn(const void *start, const char *path);
692
441edcb5
ZK
693static const struct dm_config_node *_find_config_node(const void *start,
694 const char *path)
e59e2f7c
PR
695{
696 const char *e;
697 const struct dm_config_node *cn = start;
698 const struct dm_config_node *cn_found = NULL;
699
700 while (cn) {
701 /* trim any leading slashes */
702 while (*path && (*path == sep))
703 path++;
704
705 /* find the end of this segment */
706 for (e = path; *e && (*e != sep); e++) ;
707
708 /* hunt for the node */
709 cn_found = NULL;
710 while (cn) {
711 if (_tok_match(cn->key, path, e)) {
712 /* Inefficient */
713 if (!cn_found)
714 cn_found = cn;
715 else
716 log_warn("WARNING: Ignoring duplicate"
717 " config node: %s ("
718 "seeking %s)", cn->key, path);
719 }
720
721 cn = cn->sib;
722 }
723
724 if (cn_found && *e)
725 cn = cn_found->child;
726 else
727 break; /* don't move into the last node */
728
729 path = e;
730 }
731
441edcb5 732 return cn_found;
e59e2f7c
PR
733}
734
441edcb5 735static const struct dm_config_node *_find_first_config_node(const void *start, const char *path)
e59e2f7c
PR
736{
737 const struct dm_config_tree *cft = start;
441edcb5 738 const struct dm_config_node *cn = NULL;
e59e2f7c
PR
739
740 while (cft) {
741 if ((cn = _find_config_node(cft->root, path)))
742 return cn;
743 cft = cft->cascade;
744 }
745
746 return NULL;
747}
748
fe8f5dbe 749static const char *_find_config_str(const void *start, node_lookup_fn find_fn,
7ad1c43b 750 const char *path, const char *fail, int allow_empty)
e59e2f7c 751{
fe8f5dbe 752 const struct dm_config_node *n = find_fn(start, path);
e59e2f7c 753
ebf55527
AK
754 /* Empty strings are ignored if allow_empty is set */
755 if (n && n->v) {
756 if ((n->v->type == DM_CFG_STRING) &&
757 (allow_empty || (*n->v->v.str))) {
758 log_very_verbose("Setting %s to %s", path, n->v->v.str);
759 return n->v->v.str;
760 }
761 if ((n->v->type != DM_CFG_STRING) || (!allow_empty && fail))
762 log_warn("WARNING: Ignoring unsupported value for %s.", path);
763 }
e59e2f7c
PR
764
765 if (fail)
766 log_very_verbose("%s not found in config: defaulting to %s",
767 path, fail);
768 return fail;
769}
770
771const char *dm_config_find_str(const struct dm_config_node *cn,
772 const char *path, const char *fail)
773{
7ad1c43b 774 return _find_config_str(cn, _find_config_node, path, fail, 0);
e59e2f7c
PR
775}
776
99a150fc
ZK
777const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn,
778 const char *path, const char *fail)
779{
780 return _find_config_str(cn, _find_config_node, path, fail, 1);
781}
782
fe8f5dbe 783static int64_t _find_config_int64(const void *start, node_lookup_fn find,
e59e2f7c
PR
784 const char *path, int64_t fail)
785{
786 const struct dm_config_node *n = find(start, path);
787
788 if (n && n->v && n->v->type == DM_CFG_INT) {
789 log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
790 return n->v->v.i;
791 }
792
793 log_very_verbose("%s not found in config: defaulting to %" PRId64,
794 path, fail);
795 return fail;
796}
797
fe8f5dbe 798static float _find_config_float(const void *start, node_lookup_fn find,
e59e2f7c
PR
799 const char *path, float fail)
800{
801 const struct dm_config_node *n = find(start, path);
802
803 if (n && n->v && n->v->type == DM_CFG_FLOAT) {
fe8f5dbe
AK
804 log_very_verbose("Setting %s to %f", path, n->v->v.f);
805 return n->v->v.f;
e59e2f7c
PR
806 }
807
808 log_very_verbose("%s not found in config: defaulting to %f",
809 path, fail);
810
811 return fail;
812
813}
814
815static int _str_in_array(const char *str, const char * const values[])
816{
817 int i;
818
819 for (i = 0; values[i]; i++)
820 if (!strcasecmp(str, values[i]))
821 return 1;
822
823 return 0;
824}
825
826static int _str_to_bool(const char *str, int fail)
827{
828 const char * const _true_values[] = { "y", "yes", "on", "true", NULL };
829 const char * const _false_values[] = { "n", "no", "off", "false", NULL };
830
831 if (_str_in_array(str, _true_values))
832 return 1;
833
834 if (_str_in_array(str, _false_values))
835 return 0;
836
837 return fail;
838}
839
fe8f5dbe 840static int _find_config_bool(const void *start, node_lookup_fn find,
e59e2f7c
PR
841 const char *path, int fail)
842{
843 const struct dm_config_node *n = find(start, path);
844 const struct dm_config_value *v;
845
846 if (!n)
847 return fail;
848
849 v = n->v;
850
851 switch (v->type) {
852 case DM_CFG_INT:
853 return v->v.i ? 1 : 0;
854
855 case DM_CFG_STRING:
856 return _str_to_bool(v->v.str, fail);
00ab1e3f
AK
857 default:
858 ;
e59e2f7c
PR
859 }
860
861 return fail;
862}
863
864/***********************************
865 * node-based lookup
866 **/
867
00ab1e3f 868struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn,
e68a6fbf 869 const char *path)
e59e2f7c 870{
441edcb5 871 return (struct dm_config_node *) _find_config_node(cn, path);
e59e2f7c
PR
872}
873
874int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail)
875{
876 /* FIXME Add log_error message on overflow */
877 return (int) _find_config_int64(cn, _find_config_node, path, (int64_t) fail);
878}
879
82326847
PR
880int64_t dm_config_find_int64(const struct dm_config_node *cn, const char *path, int64_t fail)
881{
882 return _find_config_int64(cn, _find_config_node, path, fail);
883}
884
e59e2f7c
PR
885float dm_config_find_float(const struct dm_config_node *cn, const char *path,
886 float fail)
887{
888 return _find_config_float(cn, _find_config_node, path, fail);
889}
890
891int dm_config_find_bool(const struct dm_config_node *cn, const char *path, int fail)
892{
893 return _find_config_bool(cn, _find_config_node, path, fail);
894}
895
896/***********************************
897 * tree-based lookup
898 **/
899
900const struct dm_config_node *dm_config_tree_find_node(const struct dm_config_tree *cft,
901 const char *path)
902{
903 return _find_first_config_node(cft, path);
904}
905
906const char *dm_config_tree_find_str(const struct dm_config_tree *cft, const char *path,
907 const char *fail)
908{
7ad1c43b
ZK
909 return _find_config_str(cft, _find_first_config_node, path, fail, 0);
910}
911
912const char *dm_config_tree_find_str_allow_empty(const struct dm_config_tree *cft, const char *path,
913 const char *fail)
914{
915 return _find_config_str(cft, _find_first_config_node, path, fail, 1);
e59e2f7c
PR
916}
917
918int dm_config_tree_find_int(const struct dm_config_tree *cft, const char *path, int fail)
919{
920 /* FIXME Add log_error message on overflow */
921 return (int) _find_config_int64(cft, _find_first_config_node, path, (int64_t) fail);
922}
923
924int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft, const char *path, int64_t fail)
925{
926 return _find_config_int64(cft, _find_first_config_node, path, fail);
927}
928
929float dm_config_tree_find_float(const struct dm_config_tree *cft, const char *path,
930 float fail)
931{
932 return _find_config_float(cft, _find_first_config_node, path, fail);
933}
934
935int dm_config_tree_find_bool(const struct dm_config_tree *cft, const char *path, int fail)
936{
937 return _find_config_bool(cft, _find_first_config_node, path, fail);
938}
939
940/************************************/
941
942
943int dm_config_get_uint32(const struct dm_config_node *cn, const char *path,
97a4b516 944 uint32_t *result)
e59e2f7c
PR
945{
946 const struct dm_config_node *n;
947
97a4b516 948 n = _find_config_node(cn, path);
e59e2f7c
PR
949
950 if (!n || !n->v || n->v->type != DM_CFG_INT)
951 return 0;
952
864ec23e
PR
953 if (result)
954 *result = n->v->v.i;
e59e2f7c
PR
955 return 1;
956}
957
958int dm_config_get_uint64(const struct dm_config_node *cn, const char *path,
959 uint64_t *result)
960{
961 const struct dm_config_node *n;
962
97a4b516 963 n = _find_config_node(cn, path);
e59e2f7c
PR
964
965 if (!n || !n->v || n->v->type != DM_CFG_INT)
966 return 0;
967
864ec23e
PR
968 if (result)
969 *result = (uint64_t) n->v->v.i;
e59e2f7c
PR
970 return 1;
971}
972
973int dm_config_get_str(const struct dm_config_node *cn, const char *path,
974 const char **result)
975{
976 const struct dm_config_node *n;
977
97a4b516 978 n = _find_config_node(cn, path);
e59e2f7c
PR
979
980 if (!n || !n->v || n->v->type != DM_CFG_STRING)
981 return 0;
982
864ec23e
PR
983 if (result)
984 *result = n->v->v.str;
e59e2f7c
PR
985 return 1;
986}
987
97a4b516
PR
988int dm_config_get_list(const struct dm_config_node *cn, const char *path,
989 const struct dm_config_value **result)
990{
991 const struct dm_config_node *n;
992
993 n = _find_config_node(cn, path);
994 /* TODO when we represent single-item lists consistently, add a check
995 * for n->v->next != NULL */
996 if (!n || !n->v)
997 return 0;
998
864ec23e
PR
999 if (result)
1000 *result = n->v;
97a4b516
PR
1001 return 1;
1002}
1003
1004int dm_config_get_section(const struct dm_config_node *cn, const char *path,
1005 const struct dm_config_node **result)
1006{
1007 const struct dm_config_node *n;
1008
1009 n = _find_config_node(cn, path);
1010 if (!n || n->v)
1011 return 0;
1012
864ec23e
PR
1013 if (result)
1014 *result = n;
97a4b516
PR
1015 return 1;
1016}
1017
1018int dm_config_has_node(const struct dm_config_node *cn, const char *path)
1019{
1020 return _find_config_node(cn, path) ? 1 : 0;
1021}
1022
e59e2f7c
PR
1023/*
1024 * Convert a token type to the char it represents.
1025 */
1026static char _token_type_to_char(int type)
1027{
1028 switch (type) {
1029 case TOK_SECTION_B:
1030 return SECTION_B_CHAR;
1031 case TOK_SECTION_E:
1032 return SECTION_E_CHAR;
1033 default:
1034 return 0;
1035 }
1036}
1037
1038/*
1039 * Returns:
1040 * # of 'type' tokens in 'str'.
1041 */
1042static unsigned _count_tokens(const char *str, unsigned len, int type)
1043{
1044 char c;
1045
1046 c = _token_type_to_char(type);
1047
1048 return dm_count_chars(str, len, c);
1049}
1050
1051const char *dm_config_parent_name(const struct dm_config_node *n)
1052{
1053 return (n->parent ? n->parent->key : "(root)");
1054}
1055/*
1056 * Heuristic function to make a quick guess as to whether a text
1057 * region probably contains a valid config "section". (Useful for
1058 * scanning areas of the disk for old metadata.)
1059 * Config sections contain various tokens, may contain other sections
1060 * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
1061 * end (type 'TOK_SECTION_E') tokens. As a quick heuristic, we just
1062 * count the number of begin and end tokens, and see if they are
1063 * non-zero and the counts match.
1064 * Full validation of the section should be done with another function
1065 * (for example, read_config_fd).
1066 *
1067 * Returns:
1068 * 0 - probably is not a valid config section
1069 * 1 - probably _is_ a valid config section
1070 */
1071unsigned dm_config_maybe_section(const char *str, unsigned len)
1072{
1073 int begin_count;
1074 int end_count;
1075
1076 begin_count = _count_tokens(str, len, TOK_SECTION_B);
1077 end_count = _count_tokens(str, len, TOK_SECTION_E);
1078
1079 if (begin_count && end_count && (begin_count == end_count))
1080 return 1;
1081 else
1082 return 0;
1083}
1084
807a5a7b 1085__attribute__((nonnull(1, 2)))
e59e2f7c
PR
1086static struct dm_config_value *_clone_config_value(struct dm_pool *mem,
1087 const struct dm_config_value *v)
1088{
1089 struct dm_config_value *new_cv;
1090
e59e2f7c
PR
1091 if (!(new_cv = _create_value(mem))) {
1092 log_error("Failed to clone config value.");
1093 return NULL;
1094 }
1095
1096 new_cv->type = v->type;
1097 if (v->type == DM_CFG_STRING) {
1098 if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
1099 log_error("Failed to clone config string value.");
1100 return NULL;
1101 }
1102 } else
1103 new_cv->v = v->v;
1104
1105 if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
1106 return_NULL;
1107
1108 return new_cv;
1109}
1110
1111struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *cn, int siblings)
1112{
1113 struct dm_config_node *new_cn;
1114
d2c25f02
ZK
1115 if (!cn) {
1116 log_error("Cannot clone NULL config node.");
e59e2f7c 1117 return NULL;
d2c25f02 1118 }
e59e2f7c
PR
1119
1120 if (!(new_cn = _create_node(mem))) {
1121 log_error("Failed to clone config node.");
1122 return NULL;
1123 }
1124
1125 if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
1126 log_error("Failed to clone config node key.");
1127 return NULL;
1128 }
1129
1130 if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
1131 (cn->child && !(new_cn->child = dm_config_clone_node_with_mem(mem, cn->child, 1))) ||
1132 (siblings && cn->sib && !(new_cn->sib = dm_config_clone_node_with_mem(mem, cn->sib, siblings))))
1133 return_NULL; /* 'new_cn' released with mem pool */
1134
1135 return new_cn;
1136}
1137
1138struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *node, int sib)
1139{
845b1df6 1140 return dm_config_clone_node_with_mem(cft->mem, node, sib);
e59e2f7c
PR
1141}
1142
1143struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key)
1144{
e59e2f7c
PR
1145 struct dm_config_node *cn;
1146
845b1df6 1147 if (!(cn = _create_node(cft->mem))) {
e59e2f7c
PR
1148 log_error("Failed to create config node.");
1149 return NULL;
1150 }
845b1df6 1151 if (!(cn->key = dm_pool_strdup(cft->mem, key))) {
e59e2f7c
PR
1152 log_error("Failed to create config node's key.");
1153 return NULL;
1154 }
845b1df6 1155 if (!(cn->v = _create_value(cft->mem))) {
e59e2f7c
PR
1156 log_error("Failed to create config node's value.");
1157 return NULL;
1158 }
1159 cn->parent = NULL;
1160 cn->v->type = DM_CFG_INT;
1161 cn->v->v.i = 0;
1162 cn->v->next = NULL;
1163 return cn;
1164}
1165
1166struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft)
1167{
845b1df6 1168 return _create_value(cft->mem);
e59e2f7c
PR
1169}
1170
1171struct dm_pool *dm_config_memory(struct dm_config_tree *cft)
1172{
845b1df6 1173 return cft->mem;
e59e2f7c 1174}
This page took 2.598196 seconds and 5 git commands to generate.