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