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