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 } 1354