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 append_cf_section(cp, sp); 499 500 sp->name = strdup(key); 501 if (sp->name == NULL) { 502 SPDK_ERRLOG("cannot duplicate %s to sp->name\n", key); 503 return -1; 504 } 505 } 506 cp->current_section = sp; 507 508 509 sp->num = num; 510 } else { 511 /* parameters */ 512 sp = cp->current_section; 513 if (sp == NULL) { 514 SPDK_ERRLOG("unknown section\n"); 515 return -1; 516 } 517 key = spdk_strsepq(&arg, CF_DELIM_KEY); 518 if (key == NULL) { 519 SPDK_ERRLOG("broken key\n"); 520 return -1; 521 } 522 523 ip = allocate_cf_item(); 524 if (ip == NULL) { 525 SPDK_ERRLOG("cannot allocate cf item\n"); 526 return -1; 527 } 528 append_cf_item(sp, ip); 529 ip->key = strdup(key); 530 if (ip->key == NULL) { 531 SPDK_ERRLOG("cannot make duplicate of %s\n", key); 532 return -1; 533 } 534 ip->val = NULL; 535 if (arg != NULL) { 536 /* key has value(s) */ 537 while (arg != NULL) { 538 val = spdk_strsepq(&arg, CF_DELIM); 539 vp = allocate_cf_value(); 540 if (vp == NULL) { 541 SPDK_ERRLOG("cannot allocate cf value\n"); 542 return -1; 543 } 544 append_cf_value(ip, vp); 545 vp->value = strdup(val); 546 if (vp->value == NULL) { 547 SPDK_ERRLOG("cannot duplicate %s to vp->value\n", val); 548 return -1; 549 } 550 } 551 } 552 } 553 554 return 0; 555 } 556 557 static char * 558 fgets_line(FILE *fp) 559 { 560 char *dst, *dst2, *p; 561 size_t total, len; 562 563 dst = p = malloc(LIB_MAX_TMPBUF); 564 if (!dst) { 565 return NULL; 566 } 567 568 dst[0] = '\0'; 569 total = 0; 570 571 while (fgets(p, LIB_MAX_TMPBUF, fp) != NULL) { 572 len = strlen(p); 573 total += len; 574 if (len + 1 < LIB_MAX_TMPBUF || dst[total - 1] == '\n') { 575 dst2 = realloc(dst, total + 1); 576 if (!dst2) { 577 free(dst); 578 return NULL; 579 } else { 580 return dst2; 581 } 582 } 583 584 dst2 = realloc(dst, total + LIB_MAX_TMPBUF); 585 if (!dst2) { 586 free(dst); 587 return NULL; 588 } else { 589 dst = dst2; 590 } 591 592 p = dst + total; 593 } 594 595 if (feof(fp) && total != 0) { 596 dst2 = realloc(dst, total + 2); 597 if (!dst2) { 598 free(dst); 599 return NULL; 600 } else { 601 dst = dst2; 602 } 603 604 dst[total] = '\n'; 605 dst[total + 1] = '\0'; 606 return dst; 607 } 608 609 free(dst); 610 611 return NULL; 612 } 613 614 int 615 spdk_conf_read(struct spdk_conf *cp, const char *file) 616 { 617 FILE *fp; 618 char *lp, *p; 619 char *lp2, *q; 620 int line; 621 int n, n2; 622 623 if (file == NULL || file[0] == '\0') { 624 return -1; 625 } 626 SPDK_ERRLOG("INI configuration has been deprecated and will be removed in a future release. Please switch to JSON-RPC.\n"); 627 628 fp = fopen(file, "r"); 629 if (fp == NULL) { 630 SPDK_ERRLOG("open error: %s\n", file); 631 return -1; 632 } 633 634 cp->file = strdup(file); 635 if (cp->file == NULL) { 636 SPDK_ERRLOG("cannot duplicate %s to cp->file\n", file); 637 fclose(fp); 638 return -1; 639 } 640 641 line = 1; 642 while ((lp = fgets_line(fp)) != NULL) { 643 /* skip spaces */ 644 for (p = lp; *p != '\0' && isspace((int) *p); p++) 645 ; 646 /* skip comment, empty line */ 647 if (p[0] == '#' || p[0] == '\0') { 648 goto next_line; 649 } 650 651 /* concatenate line end with '\' */ 652 n = strlen(p); 653 while (n > 2 && p[n - 1] == '\n' && p[n - 2] == '\\') { 654 n -= 2; 655 lp2 = fgets_line(fp); 656 if (lp2 == NULL) { 657 break; 658 } 659 660 line++; 661 n2 = strlen(lp2); 662 663 q = malloc(n + n2 + 1); 664 if (!q) { 665 free(lp2); 666 free(lp); 667 SPDK_ERRLOG("malloc failed at line %d of %s\n", line, cp->file); 668 fclose(fp); 669 return -1; 670 } 671 672 memcpy(q, p, n); 673 memcpy(q + n, lp2, n2); 674 q[n + n2] = '\0'; 675 free(lp2); 676 free(lp); 677 p = lp = q; 678 n += n2; 679 } 680 681 /* parse one line */ 682 if (parse_line(cp, p) < 0) { 683 SPDK_ERRLOG("parse error at line %d of %s\n", line, cp->file); 684 } 685 next_line: 686 line++; 687 free(lp); 688 } 689 690 fclose(fp); 691 return 0; 692 } 693 694 void 695 spdk_conf_set_as_default(struct spdk_conf *cp) 696 { 697 default_config = cp; 698 } 699 700 void 701 spdk_conf_disable_sections_merge(struct spdk_conf *cp) 702 { 703 cp->merge_sections = false; 704 } 705