1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>. 5 * Copyright (c) Intel Corporation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name of Intel Corporation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "spdk/stdinc.h" 36 37 #include "spdk/conf.h" 38 #include "spdk/string.h" 39 #include "spdk/log.h" 40 41 struct spdk_conf_value { 42 struct spdk_conf_value *next; 43 char *value; 44 }; 45 46 struct spdk_conf_item { 47 struct spdk_conf_item *next; 48 char *key; 49 struct spdk_conf_value *val; 50 }; 51 52 struct spdk_conf_section { 53 struct spdk_conf_section *next; 54 char *name; 55 int num; 56 struct spdk_conf_item *item; 57 }; 58 59 struct spdk_conf { 60 char *file; 61 struct spdk_conf_section *current_section; 62 struct spdk_conf_section *section; 63 bool merge_sections; 64 }; 65 66 #define CF_DELIM " \t" 67 #define CF_DELIM_KEY " \t=" 68 69 #define LIB_MAX_TMPBUF 1024 70 71 static struct spdk_conf *default_config = NULL; 72 73 struct spdk_conf * 74 spdk_conf_allocate(void) 75 { 76 struct spdk_conf *ret = calloc(1, sizeof(struct spdk_conf)); 77 78 if (ret) { 79 ret->merge_sections = true; 80 } 81 82 return ret; 83 } 84 85 static void 86 free_conf_value(struct spdk_conf_value *vp) 87 { 88 if (vp == NULL) { 89 return; 90 } 91 92 if (vp->value) { 93 free(vp->value); 94 } 95 96 free(vp); 97 } 98 99 static void 100 free_all_conf_value(struct spdk_conf_value *vp) 101 { 102 struct spdk_conf_value *next; 103 104 if (vp == NULL) { 105 return; 106 } 107 108 while (vp != NULL) { 109 next = vp->next; 110 free_conf_value(vp); 111 vp = next; 112 } 113 } 114 115 static void 116 free_conf_item(struct spdk_conf_item *ip) 117 { 118 if (ip == NULL) { 119 return; 120 } 121 122 if (ip->val != NULL) { 123 free_all_conf_value(ip->val); 124 } 125 126 if (ip->key != NULL) { 127 free(ip->key); 128 } 129 130 free(ip); 131 } 132 133 static void 134 free_all_conf_item(struct spdk_conf_item *ip) 135 { 136 struct spdk_conf_item *next; 137 138 if (ip == NULL) { 139 return; 140 } 141 142 while (ip != NULL) { 143 next = ip->next; 144 free_conf_item(ip); 145 ip = next; 146 } 147 } 148 149 static void 150 free_conf_section(struct spdk_conf_section *sp) 151 { 152 if (sp == NULL) { 153 return; 154 } 155 156 if (sp->item) { 157 free_all_conf_item(sp->item); 158 } 159 160 if (sp->name) { 161 free(sp->name); 162 } 163 164 free(sp); 165 } 166 167 static void 168 free_all_conf_section(struct spdk_conf_section *sp) 169 { 170 struct spdk_conf_section *next; 171 172 if (sp == NULL) { 173 return; 174 } 175 176 while (sp != NULL) { 177 next = sp->next; 178 free_conf_section(sp); 179 sp = next; 180 } 181 } 182 183 void 184 spdk_conf_free(struct spdk_conf *cp) 185 { 186 if (cp == NULL) { 187 return; 188 } 189 190 if (cp->section != NULL) { 191 free_all_conf_section(cp->section); 192 } 193 194 if (cp->file != NULL) { 195 free(cp->file); 196 } 197 198 free(cp); 199 } 200 201 static struct spdk_conf_section * 202 allocate_cf_section(void) 203 { 204 return calloc(1, sizeof(struct spdk_conf_section)); 205 } 206 207 static struct spdk_conf_item * 208 allocate_cf_item(void) 209 { 210 return calloc(1, sizeof(struct spdk_conf_item)); 211 } 212 213 static struct spdk_conf_value * 214 allocate_cf_value(void) 215 { 216 return calloc(1, sizeof(struct spdk_conf_value)); 217 } 218 219 220 #define CHECK_CP_OR_USE_DEFAULT(cp) (((cp) == NULL) && (default_config != NULL)) ? default_config : (cp) 221 222 struct spdk_conf_section * 223 spdk_conf_find_section(struct spdk_conf *cp, const char *name) 224 { 225 struct spdk_conf_section *sp; 226 227 if (name == NULL || name[0] == '\0') { 228 return NULL; 229 } 230 231 cp = CHECK_CP_OR_USE_DEFAULT(cp); 232 if (cp == NULL) { 233 return NULL; 234 } 235 236 for (sp = cp->section; sp != NULL; sp = sp->next) { 237 if (sp->name != NULL && sp->name[0] == name[0] 238 && strcasecmp(sp->name, name) == 0) { 239 return sp; 240 } 241 } 242 243 return NULL; 244 } 245 246 struct spdk_conf_section * 247 spdk_conf_first_section(struct spdk_conf *cp) 248 { 249 cp = CHECK_CP_OR_USE_DEFAULT(cp); 250 if (cp == NULL) { 251 return NULL; 252 } 253 254 return cp->section; 255 } 256 257 struct spdk_conf_section * 258 spdk_conf_next_section(struct spdk_conf_section *sp) 259 { 260 if (sp == NULL) { 261 return NULL; 262 } 263 264 return sp->next; 265 } 266 267 static void 268 append_cf_section(struct spdk_conf *cp, struct spdk_conf_section *sp) 269 { 270 struct spdk_conf_section *last; 271 272 cp = CHECK_CP_OR_USE_DEFAULT(cp); 273 if (cp == NULL) { 274 SPDK_ERRLOG("cp == NULL\n"); 275 return; 276 } 277 278 if (cp->section == NULL) { 279 cp->section = sp; 280 return; 281 } 282 283 for (last = cp->section; last->next != NULL; last = last->next) 284 ; 285 last->next = sp; 286 } 287 288 static struct spdk_conf_item * 289 find_cf_nitem(struct spdk_conf_section *sp, const char *key, int idx) 290 { 291 struct spdk_conf_item *ip; 292 int i; 293 294 if (key == NULL || key[0] == '\0') { 295 return NULL; 296 } 297 298 i = 0; 299 for (ip = sp->item; ip != NULL; ip = ip->next) { 300 if (ip->key != NULL && ip->key[0] == key[0] 301 && strcasecmp(ip->key, key) == 0) { 302 if (i == idx) { 303 return ip; 304 } 305 i++; 306 } 307 } 308 309 return NULL; 310 } 311 312 static void 313 append_cf_item(struct spdk_conf_section *sp, struct spdk_conf_item *ip) 314 { 315 struct spdk_conf_item *last; 316 317 if (sp == NULL) { 318 return; 319 } 320 321 if (sp->item == NULL) { 322 sp->item = ip; 323 return; 324 } 325 326 for (last = sp->item; last->next != NULL; last = last->next) 327 ; 328 last->next = ip; 329 } 330 331 static void 332 append_cf_value(struct spdk_conf_item *ip, struct spdk_conf_value *vp) 333 { 334 struct spdk_conf_value *last; 335 336 if (ip == NULL) { 337 return; 338 } 339 340 if (ip->val == NULL) { 341 ip->val = vp; 342 return; 343 } 344 345 for (last = ip->val; last->next != NULL; last = last->next) 346 ; 347 last->next = vp; 348 } 349 350 bool 351 spdk_conf_section_match_prefix(const struct spdk_conf_section *sp, const char *name_prefix) 352 { 353 return strncasecmp(sp->name, name_prefix, strlen(name_prefix)) == 0; 354 } 355 356 const char * 357 spdk_conf_section_get_name(const struct spdk_conf_section *sp) 358 { 359 return sp->name; 360 } 361 362 int 363 spdk_conf_section_get_num(const struct spdk_conf_section *sp) 364 { 365 return sp->num; 366 } 367 368 char * 369 spdk_conf_section_get_nmval(struct spdk_conf_section *sp, const char *key, int idx1, int idx2) 370 { 371 struct spdk_conf_item *ip; 372 struct spdk_conf_value *vp; 373 int i; 374 375 ip = find_cf_nitem(sp, key, idx1); 376 if (ip == NULL) { 377 return NULL; 378 } 379 380 vp = ip->val; 381 if (vp == NULL) { 382 return NULL; 383 } 384 385 for (i = 0; vp != NULL; vp = vp->next, i++) { 386 if (i == idx2) { 387 return vp->value; 388 } 389 } 390 391 return NULL; 392 } 393 394 char * 395 spdk_conf_section_get_nval(struct spdk_conf_section *sp, const char *key, int idx) 396 { 397 struct spdk_conf_item *ip; 398 struct spdk_conf_value *vp; 399 400 ip = find_cf_nitem(sp, key, idx); 401 if (ip == NULL) { 402 return NULL; 403 } 404 405 vp = ip->val; 406 if (vp == NULL) { 407 return NULL; 408 } 409 410 return vp->value; 411 } 412 413 char * 414 spdk_conf_section_get_val(struct spdk_conf_section *sp, const char *key) 415 { 416 return spdk_conf_section_get_nval(sp, key, 0); 417 } 418 419 int 420 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key) 421 { 422 const char *v; 423 int value; 424 425 v = spdk_conf_section_get_nval(sp, key, 0); 426 if (v == NULL) { 427 return -1; 428 } 429 430 value = (int)spdk_strtol(v, 10); 431 return value; 432 } 433 434 bool 435 spdk_conf_section_get_boolval(struct spdk_conf_section *sp, const char *key, bool default_val) 436 { 437 const char *v; 438 439 v = spdk_conf_section_get_nval(sp, key, 0); 440 if (v == NULL) { 441 return default_val; 442 } 443 444 if (!strcasecmp(v, "Yes") || !strcasecmp(v, "Y") || !strcasecmp(v, "True")) { 445 return true; 446 } 447 448 if (!strcasecmp(v, "No") || !strcasecmp(v, "N") || !strcasecmp(v, "False")) { 449 return false; 450 } 451 452 return default_val; 453 } 454 455 static int 456 parse_line(struct spdk_conf *cp, char *lp) 457 { 458 struct spdk_conf_section *sp; 459 struct spdk_conf_item *ip; 460 struct spdk_conf_value *vp; 461 char *arg; 462 char *key; 463 char *val; 464 char *p; 465 int num; 466 467 arg = spdk_str_trim(lp); 468 if (arg == NULL) { 469 SPDK_ERRLOG("no section\n"); 470 return -1; 471 } 472 473 if (arg[0] == '[') { 474 /* section */ 475 arg++; 476 key = spdk_strsepq(&arg, "]"); 477 if (key == NULL || arg != NULL) { 478 SPDK_ERRLOG("broken section\n"); 479 return -1; 480 } 481 /* determine section number */ 482 for (p = key; *p != '\0' && !isdigit((int) *p); p++) 483 ; 484 if (*p != '\0') { 485 num = (int)spdk_strtol(p, 10); 486 } else { 487 num = 0; 488 } 489 490 if (cp->merge_sections) { 491 sp = spdk_conf_find_section(cp, key); 492 } else { 493 sp = NULL; 494 } 495 496 if (sp == NULL) { 497 sp = allocate_cf_section(); 498 if (sp == NULL) { 499 SPDK_ERRLOG("cannot allocate cf section\n"); 500 return -1; 501 } 502 append_cf_section(cp, sp); 503 504 sp->name = strdup(key); 505 if (sp->name == NULL) { 506 SPDK_ERRLOG("cannot duplicate %s to sp->name\n", key); 507 return -1; 508 } 509 } 510 cp->current_section = sp; 511 512 513 sp->num = num; 514 } else { 515 /* parameters */ 516 sp = cp->current_section; 517 if (sp == NULL) { 518 SPDK_ERRLOG("unknown section\n"); 519 return -1; 520 } 521 key = spdk_strsepq(&arg, CF_DELIM_KEY); 522 if (key == NULL) { 523 SPDK_ERRLOG("broken key\n"); 524 return -1; 525 } 526 527 ip = allocate_cf_item(); 528 if (ip == NULL) { 529 SPDK_ERRLOG("cannot allocate cf item\n"); 530 return -1; 531 } 532 append_cf_item(sp, ip); 533 ip->key = strdup(key); 534 if (ip->key == NULL) { 535 SPDK_ERRLOG("cannot make duplicate of %s\n", key); 536 return -1; 537 } 538 ip->val = NULL; 539 if (arg != NULL) { 540 /* key has value(s) */ 541 while (arg != NULL) { 542 val = spdk_strsepq(&arg, CF_DELIM); 543 vp = allocate_cf_value(); 544 if (vp == NULL) { 545 SPDK_ERRLOG("cannot allocate cf value\n"); 546 return -1; 547 } 548 append_cf_value(ip, vp); 549 vp->value = strdup(val); 550 if (vp->value == NULL) { 551 SPDK_ERRLOG("cannot duplicate %s to vp->value\n", val); 552 return -1; 553 } 554 } 555 } 556 } 557 558 return 0; 559 } 560 561 static char * 562 fgets_line(FILE *fp) 563 { 564 char *dst, *dst2, *p; 565 size_t total, len; 566 567 dst = p = malloc(LIB_MAX_TMPBUF); 568 if (!dst) { 569 return NULL; 570 } 571 572 dst[0] = '\0'; 573 total = 0; 574 575 while (fgets(p, LIB_MAX_TMPBUF, fp) != NULL) { 576 len = strlen(p); 577 total += len; 578 if (len + 1 < LIB_MAX_TMPBUF || dst[total - 1] == '\n') { 579 dst2 = realloc(dst, total + 1); 580 if (!dst2) { 581 free(dst); 582 return NULL; 583 } else { 584 return dst2; 585 } 586 } 587 588 dst2 = realloc(dst, total + LIB_MAX_TMPBUF); 589 if (!dst2) { 590 free(dst); 591 return NULL; 592 } else { 593 dst = dst2; 594 } 595 596 p = dst + total; 597 } 598 599 if (feof(fp) && total != 0) { 600 dst2 = realloc(dst, total + 2); 601 if (!dst2) { 602 free(dst); 603 return NULL; 604 } else { 605 dst = dst2; 606 } 607 608 dst[total] = '\n'; 609 dst[total + 1] = '\0'; 610 return dst; 611 } 612 613 free(dst); 614 615 return NULL; 616 } 617 618 int 619 spdk_conf_read(struct spdk_conf *cp, const char *file) 620 { 621 FILE *fp; 622 char *lp, *p; 623 char *lp2, *q; 624 int line; 625 int n, n2; 626 627 if (file == NULL || file[0] == '\0') { 628 return -1; 629 } 630 631 fp = fopen(file, "r"); 632 if (fp == NULL) { 633 SPDK_ERRLOG("open error: %s\n", file); 634 return -1; 635 } 636 637 cp->file = strdup(file); 638 if (cp->file == NULL) { 639 SPDK_ERRLOG("cannot duplicate %s to cp->file\n", file); 640 fclose(fp); 641 return -1; 642 } 643 644 line = 1; 645 while ((lp = fgets_line(fp)) != NULL) { 646 /* skip spaces */ 647 for (p = lp; *p != '\0' && isspace((int) *p); p++) 648 ; 649 /* skip comment, empty line */ 650 if (p[0] == '#' || p[0] == '\0') { 651 goto next_line; 652 } 653 654 /* concatenate line end with '\' */ 655 n = strlen(p); 656 while (n > 2 && p[n - 1] == '\n' && p[n - 2] == '\\') { 657 n -= 2; 658 lp2 = fgets_line(fp); 659 if (lp2 == NULL) { 660 break; 661 } 662 663 line++; 664 n2 = strlen(lp2); 665 666 q = malloc(n + n2 + 1); 667 if (!q) { 668 free(lp2); 669 free(lp); 670 SPDK_ERRLOG("malloc failed at line %d of %s\n", line, cp->file); 671 fclose(fp); 672 return -1; 673 } 674 675 memcpy(q, p, n); 676 memcpy(q + n, lp2, n2); 677 q[n + n2] = '\0'; 678 free(lp2); 679 free(lp); 680 p = lp = q; 681 n += n2; 682 } 683 684 /* parse one line */ 685 if (parse_line(cp, p) < 0) { 686 SPDK_ERRLOG("parse error at line %d of %s\n", line, cp->file); 687 } 688 next_line: 689 line++; 690 free(lp); 691 } 692 693 fclose(fp); 694 return 0; 695 } 696 697 void 698 spdk_conf_set_as_default(struct spdk_conf *cp) 699 { 700 default_config = cp; 701 } 702 703 void 704 spdk_conf_disable_sections_merge(struct spdk_conf *cp) 705 { 706 cp->merge_sections = false; 707 } 708