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 }; 64 65 #define CF_DELIM " \t" 66 67 #define LIB_MAX_TMPBUF 1024 68 69 static struct spdk_conf *default_config = NULL; 70 71 struct spdk_conf * 72 spdk_conf_allocate(void) 73 { 74 return calloc(1, sizeof(struct spdk_conf)); 75 } 76 77 static void 78 free_conf_value(struct spdk_conf_value *vp) 79 { 80 if (vp == NULL) { 81 return; 82 } 83 84 if (vp->value) { 85 free(vp->value); 86 } 87 88 free(vp); 89 } 90 91 static void 92 free_all_conf_value(struct spdk_conf_value *vp) 93 { 94 struct spdk_conf_value *next; 95 96 if (vp == NULL) { 97 return; 98 } 99 100 while (vp != NULL) { 101 next = vp->next; 102 free_conf_value(vp); 103 vp = next; 104 } 105 } 106 107 static void 108 free_conf_item(struct spdk_conf_item *ip) 109 { 110 if (ip == NULL) { 111 return; 112 } 113 114 if (ip->val != NULL) { 115 free_all_conf_value(ip->val); 116 } 117 118 if (ip->key != NULL) { 119 free(ip->key); 120 } 121 122 free(ip); 123 } 124 125 static void 126 free_all_conf_item(struct spdk_conf_item *ip) 127 { 128 struct spdk_conf_item *next; 129 130 if (ip == NULL) { 131 return; 132 } 133 134 while (ip != NULL) { 135 next = ip->next; 136 free_conf_item(ip); 137 ip = next; 138 } 139 } 140 141 static void 142 free_conf_section(struct spdk_conf_section *sp) 143 { 144 if (sp == NULL) { 145 return; 146 } 147 148 if (sp->item) { 149 free_all_conf_item(sp->item); 150 } 151 152 if (sp->name) { 153 free(sp->name); 154 } 155 156 free(sp); 157 } 158 159 static void 160 free_all_conf_section(struct spdk_conf_section *sp) 161 { 162 struct spdk_conf_section *next; 163 164 if (sp == NULL) { 165 return; 166 } 167 168 while (sp != NULL) { 169 next = sp->next; 170 free_conf_section(sp); 171 sp = next; 172 } 173 } 174 175 void 176 spdk_conf_free(struct spdk_conf *cp) 177 { 178 if (cp == NULL) { 179 return; 180 } 181 182 if (cp->section != NULL) { 183 free_all_conf_section(cp->section); 184 } 185 186 if (cp->file != NULL) { 187 free(cp->file); 188 } 189 190 free(cp); 191 } 192 193 static struct spdk_conf_section * 194 allocate_cf_section(void) 195 { 196 return calloc(1, sizeof(struct spdk_conf_section)); 197 } 198 199 static struct spdk_conf_item * 200 allocate_cf_item(void) 201 { 202 return calloc(1, sizeof(struct spdk_conf_item)); 203 } 204 205 static struct spdk_conf_value * 206 allocate_cf_value(void) 207 { 208 return calloc(1, sizeof(struct spdk_conf_value)); 209 } 210 211 212 #define CHECK_CP_OR_USE_DEFAULT(cp) (((cp) == NULL) && (default_config != NULL)) ? default_config : (cp) 213 214 struct spdk_conf_section * 215 spdk_conf_find_section(struct spdk_conf *cp, const char *name) 216 { 217 struct spdk_conf_section *sp; 218 219 if (name == NULL || name[0] == '\0') { 220 return NULL; 221 } 222 223 cp = CHECK_CP_OR_USE_DEFAULT(cp); 224 if (cp == NULL) { 225 return NULL; 226 } 227 228 for (sp = cp->section; sp != NULL; sp = sp->next) { 229 if (sp->name != NULL && sp->name[0] == name[0] 230 && strcasecmp(sp->name, name) == 0) { 231 return sp; 232 } 233 } 234 235 return NULL; 236 } 237 238 struct spdk_conf_section * 239 spdk_conf_first_section(struct spdk_conf *cp) 240 { 241 cp = CHECK_CP_OR_USE_DEFAULT(cp); 242 if (cp == NULL) { 243 return NULL; 244 } 245 246 return cp->section; 247 } 248 249 struct spdk_conf_section * 250 spdk_conf_next_section(struct spdk_conf_section *sp) 251 { 252 if (sp == NULL) { 253 return NULL; 254 } 255 256 return sp->next; 257 } 258 259 static void 260 append_cf_section(struct spdk_conf *cp, struct spdk_conf_section *sp) 261 { 262 struct spdk_conf_section *last; 263 264 cp = CHECK_CP_OR_USE_DEFAULT(cp); 265 if (cp == NULL) { 266 SPDK_ERRLOG("cp == NULL\n"); 267 return; 268 } 269 270 if (cp->section == NULL) { 271 cp->section = sp; 272 return; 273 } 274 275 for (last = cp->section; last->next != NULL; last = last->next) 276 ; 277 last->next = sp; 278 } 279 280 static struct spdk_conf_item * 281 find_cf_nitem(struct spdk_conf_section *sp, const char *key, int idx) 282 { 283 struct spdk_conf_item *ip; 284 int i; 285 286 if (key == NULL || key[0] == '\0') { 287 return NULL; 288 } 289 290 i = 0; 291 for (ip = sp->item; ip != NULL; ip = ip->next) { 292 if (ip->key != NULL && ip->key[0] == key[0] 293 && strcasecmp(ip->key, key) == 0) { 294 if (i == idx) { 295 return ip; 296 } 297 i++; 298 } 299 } 300 301 return NULL; 302 } 303 304 static void 305 append_cf_item(struct spdk_conf_section *sp, struct spdk_conf_item *ip) 306 { 307 struct spdk_conf_item *last; 308 309 if (sp == NULL) { 310 return; 311 } 312 313 if (sp->item == NULL) { 314 sp->item = ip; 315 return; 316 } 317 318 for (last = sp->item; last->next != NULL; last = last->next) 319 ; 320 last->next = ip; 321 } 322 323 static void 324 append_cf_value(struct spdk_conf_item *ip, struct spdk_conf_value *vp) 325 { 326 struct spdk_conf_value *last; 327 328 if (ip == NULL) { 329 return; 330 } 331 332 if (ip->val == NULL) { 333 ip->val = vp; 334 return; 335 } 336 337 for (last = ip->val; last->next != NULL; last = last->next) 338 ; 339 last->next = vp; 340 } 341 342 bool 343 spdk_conf_section_match_prefix(const struct spdk_conf_section *sp, const char *name_prefix) 344 { 345 return strncasecmp(sp->name, name_prefix, strlen(name_prefix)) == 0; 346 } 347 348 const char * 349 spdk_conf_section_get_name(const struct spdk_conf_section *sp) 350 { 351 return sp->name; 352 } 353 354 int 355 spdk_conf_section_get_num(const struct spdk_conf_section *sp) 356 { 357 return sp->num; 358 } 359 360 char * 361 spdk_conf_section_get_nmval(struct spdk_conf_section *sp, const char *key, int idx1, int idx2) 362 { 363 struct spdk_conf_item *ip; 364 struct spdk_conf_value *vp; 365 int i; 366 367 ip = find_cf_nitem(sp, key, idx1); 368 if (ip == NULL) { 369 return NULL; 370 } 371 372 vp = ip->val; 373 if (vp == NULL) { 374 return NULL; 375 } 376 377 for (i = 0; vp != NULL; vp = vp->next, i++) { 378 if (i == idx2) { 379 return vp->value; 380 } 381 } 382 383 return NULL; 384 } 385 386 char * 387 spdk_conf_section_get_nval(struct spdk_conf_section *sp, const char *key, int idx) 388 { 389 struct spdk_conf_item *ip; 390 struct spdk_conf_value *vp; 391 392 ip = find_cf_nitem(sp, key, idx); 393 if (ip == NULL) { 394 return NULL; 395 } 396 397 vp = ip->val; 398 if (vp == NULL) { 399 return NULL; 400 } 401 402 return vp->value; 403 } 404 405 char * 406 spdk_conf_section_get_val(struct spdk_conf_section *sp, const char *key) 407 { 408 return spdk_conf_section_get_nval(sp, key, 0); 409 } 410 411 int 412 spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key) 413 { 414 const char *v; 415 int value; 416 417 v = spdk_conf_section_get_nval(sp, key, 0); 418 if (v == NULL) { 419 return -1; 420 } 421 422 value = (int)strtol(v, NULL, 10); 423 return value; 424 } 425 426 bool 427 spdk_conf_section_get_boolval(struct spdk_conf_section *sp, const char *key, bool default_val) 428 { 429 const char *v; 430 431 v = spdk_conf_section_get_nval(sp, key, 0); 432 if (v == NULL) { 433 return default_val; 434 } 435 436 if (!strcasecmp(v, "Yes") || !strcasecmp(v, "Y") || !strcasecmp(v, "True")) { 437 return true; 438 } 439 440 if (!strcasecmp(v, "No") || !strcasecmp(v, "N") || !strcasecmp(v, "False")) { 441 return false; 442 } 443 444 return default_val; 445 } 446 447 static int 448 parse_line(struct spdk_conf *cp, char *lp) 449 { 450 struct spdk_conf_section *sp; 451 struct spdk_conf_item *ip; 452 struct spdk_conf_value *vp; 453 char *arg; 454 char *key; 455 char *val; 456 char *p; 457 int num; 458 459 arg = spdk_str_trim(lp); 460 if (arg == NULL) { 461 SPDK_ERRLOG("no section\n"); 462 return -1; 463 } 464 465 if (arg[0] == '[') { 466 /* section */ 467 arg++; 468 key = spdk_strsepq(&arg, "]"); 469 if (key == NULL || arg != NULL) { 470 SPDK_ERRLOG("broken section\n"); 471 return -1; 472 } 473 /* determine section number */ 474 for (p = key; *p != '\0' && !isdigit((int) *p); p++) 475 ; 476 if (*p != '\0') { 477 num = (int)strtol(p, NULL, 10); 478 } else { 479 num = 0; 480 } 481 482 sp = spdk_conf_find_section(cp, key); 483 if (sp == NULL) { 484 sp = allocate_cf_section(); 485 append_cf_section(cp, sp); 486 487 sp->name = strdup(key); 488 if (sp->name == NULL) { 489 SPDK_ERRLOG("cannot duplicate %s to sp->name\n", key); 490 return -1; 491 } 492 } 493 cp->current_section = sp; 494 495 496 sp->num = num; 497 } else { 498 /* parameters */ 499 sp = cp->current_section; 500 if (sp == NULL) { 501 SPDK_ERRLOG("unknown section\n"); 502 return -1; 503 } 504 key = spdk_strsepq(&arg, CF_DELIM); 505 if (key == NULL) { 506 SPDK_ERRLOG("broken key\n"); 507 return -1; 508 } 509 510 ip = allocate_cf_item(); 511 if (ip == NULL) { 512 SPDK_ERRLOG("cannot allocate cf item\n"); 513 return -1; 514 } 515 append_cf_item(sp, ip); 516 ip->key = strdup(key); 517 if (ip->key == NULL) { 518 SPDK_ERRLOG("cannot make duplicate of %s\n", key); 519 return -1; 520 } 521 ip->val = NULL; 522 if (arg != NULL) { 523 /* key has value(s) */ 524 while (arg != NULL) { 525 val = spdk_strsepq(&arg, CF_DELIM); 526 vp = allocate_cf_value(); 527 if (vp == NULL) { 528 SPDK_ERRLOG("cannot allocate cf value\n"); 529 return -1; 530 } 531 append_cf_value(ip, vp); 532 vp->value = strdup(val); 533 if (vp->value == NULL) { 534 SPDK_ERRLOG("cannot duplicate %s to vp->value\n", val); 535 return -1; 536 } 537 } 538 } 539 } 540 541 return 0; 542 } 543 544 static char * 545 fgets_line(FILE *fp) 546 { 547 char *dst, *dst2, *p; 548 size_t total, len; 549 550 dst = p = malloc(LIB_MAX_TMPBUF); 551 if (!dst) { 552 return NULL; 553 } 554 555 dst[0] = '\0'; 556 total = 0; 557 558 while (fgets(p, LIB_MAX_TMPBUF, fp) != NULL) { 559 len = strlen(p); 560 total += len; 561 if (len + 1 < LIB_MAX_TMPBUF || dst[total - 1] == '\n') { 562 dst2 = realloc(dst, total + 1); 563 if (!dst2) { 564 free(dst); 565 return NULL; 566 } else { 567 return dst2; 568 } 569 } 570 571 dst2 = realloc(dst, total + LIB_MAX_TMPBUF); 572 if (!dst2) { 573 free(dst); 574 return NULL; 575 } else { 576 dst = dst2; 577 } 578 579 p = dst + total; 580 } 581 582 if (feof(fp) && total != 0) { 583 dst2 = realloc(dst, total + 2); 584 if (!dst2) { 585 free(dst); 586 return NULL; 587 } else { 588 dst = dst2; 589 } 590 591 dst[total] = '\n'; 592 dst[total + 1] = '\0'; 593 return dst; 594 } 595 596 free(dst); 597 598 return NULL; 599 } 600 601 int 602 spdk_conf_read(struct spdk_conf *cp, const char *file) 603 { 604 FILE *fp; 605 char *lp, *p; 606 char *lp2, *q; 607 int line; 608 int n, n2; 609 610 if (file == NULL || file[0] == '\0') { 611 return -1; 612 } 613 614 fp = fopen(file, "r"); 615 if (fp == NULL) { 616 SPDK_ERRLOG("open error: %s\n", file); 617 return -1; 618 } 619 620 cp->file = strdup(file); 621 if (cp->file == NULL) { 622 SPDK_ERRLOG("cannot duplicate %s to cp->file\n", file); 623 fclose(fp); 624 return -1; 625 } 626 627 line = 1; 628 while ((lp = fgets_line(fp)) != NULL) { 629 /* skip spaces */ 630 for (p = lp; *p != '\0' && isspace((int) *p); p++) 631 ; 632 /* skip comment, empty line */ 633 if (p[0] == '#' || p[0] == '\0') { 634 goto next_line; 635 } 636 637 /* concatenate line end with '\' */ 638 n = strlen(p); 639 while (n > 2 && p[n - 1] == '\n' && p[n - 2] == '\\') { 640 n -= 2; 641 lp2 = fgets_line(fp); 642 if (lp2 == NULL) { 643 break; 644 } 645 646 line++; 647 n2 = strlen(lp2); 648 649 q = malloc(n + n2 + 1); 650 if (!q) { 651 free(lp2); 652 free(lp); 653 SPDK_ERRLOG("malloc failed at line %d of %s\n", line, cp->file); 654 fclose(fp); 655 return -1; 656 } 657 658 memcpy(q, p, n); 659 memcpy(q + n, lp2, n2); 660 q[n + n2] = '\0'; 661 free(lp2); 662 free(lp); 663 p = lp = q; 664 n += n2; 665 } 666 667 /* parse one line */ 668 if (parse_line(cp, p) < 0) { 669 SPDK_ERRLOG("parse error at line %d of %s\n", line, cp->file); 670 } 671 next_line: 672 line++; 673 free(lp); 674 } 675 676 fclose(fp); 677 return 0; 678 } 679 680 void 681 spdk_conf_set_as_default(struct spdk_conf *cp) 682 { 683 default_config = cp; 684 } 685