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/conf.h" 36 37 #include <ctype.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include "spdk/string.h" 44 45 #define CF_DELIM " \t" 46 47 #define LIB_MAX_TMPBUF 1024 48 49 static struct spdk_conf *default_config = NULL; 50 51 struct spdk_conf * 52 spdk_conf_allocate(void) 53 { 54 return calloc(1, sizeof(struct spdk_conf)); 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 fprintf(stderr, "%s: cp == NULL\n", __func__); 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)strtol(v, NULL, 10); 403 return value; 404 } 405 406 static int 407 parse_line(struct spdk_conf *cp, char *lp) 408 { 409 struct spdk_conf_section *sp; 410 struct spdk_conf_item *ip; 411 struct spdk_conf_value *vp; 412 char *arg; 413 char *key; 414 char *val; 415 char *p; 416 int num; 417 418 arg = spdk_str_trim(lp); 419 if (arg == NULL) { 420 fprintf(stderr, "no section\n"); 421 return -1; 422 } 423 424 if (arg[0] == '[') { 425 /* section */ 426 arg++; 427 key = spdk_strsepq(&arg, "]"); 428 if (key == NULL || arg != NULL) { 429 fprintf(stderr, "broken section\n"); 430 return -1; 431 } 432 /* determine section number */ 433 for (p = key; *p != '\0' && !isdigit((int) *p); p++) 434 ; 435 if (*p != '\0') { 436 num = (int)strtol(p, NULL, 10); 437 } else { 438 num = 0; 439 } 440 441 sp = spdk_conf_find_section(cp, key); 442 if (sp == NULL) { 443 sp = allocate_cf_section(); 444 append_cf_section(cp, sp); 445 } 446 cp->current_section = sp; 447 sp->name = strdup(key); 448 if (sp->name == NULL) { 449 perror("strdup sp->name"); 450 return -1; 451 } 452 453 sp->num = num; 454 } else { 455 /* parameters */ 456 sp = cp->current_section; 457 if (sp == NULL) { 458 fprintf(stderr, "unknown section\n"); 459 return -1; 460 } 461 key = spdk_strsepq(&arg, CF_DELIM); 462 if (key == NULL) { 463 fprintf(stderr, "broken key\n"); 464 return -1; 465 } 466 467 ip = allocate_cf_item(); 468 if (ip == NULL) { 469 fprintf(stderr, "cannot allocate cf item\n"); 470 return -1; 471 } 472 append_cf_item(sp, ip); 473 ip->key = strdup(key); 474 if (ip->key == NULL) { 475 perror("strdup ip->key"); 476 return -1; 477 } 478 ip->val = NULL; 479 if (arg != NULL) { 480 /* key has value(s) */ 481 while (arg != NULL) { 482 val = spdk_strsepq(&arg, CF_DELIM); 483 vp = allocate_cf_value(); 484 if (vp == NULL) { 485 fprintf(stderr, 486 "cannot allocate cf value\n"); 487 return -1; 488 } 489 append_cf_value(ip, vp); 490 vp->value = strdup(val); 491 if (vp->value == NULL) { 492 perror("strdup vp->value"); 493 return -1; 494 } 495 } 496 } 497 } 498 499 return 0; 500 } 501 502 static char * 503 fgets_line(FILE *fp) 504 { 505 char *dst, *dst2, *p; 506 size_t total, len; 507 508 dst = p = malloc(LIB_MAX_TMPBUF); 509 if (!dst) { 510 return NULL; 511 } 512 513 dst[0] = '\0'; 514 total = 0; 515 516 while (fgets(p, LIB_MAX_TMPBUF, fp) != NULL) { 517 len = strlen(p); 518 total += len; 519 if (len + 1 < LIB_MAX_TMPBUF || dst[total - 1] == '\n') { 520 dst2 = realloc(dst, total + 1); 521 if (!dst2) { 522 free(dst); 523 return NULL; 524 } else { 525 return dst2; 526 } 527 } 528 529 dst2 = realloc(dst, total + LIB_MAX_TMPBUF); 530 if (!dst2) { 531 free(dst); 532 return NULL; 533 } else { 534 dst = dst2; 535 } 536 537 p = dst + total; 538 } 539 540 if (feof(fp) && total != 0) { 541 dst2 = realloc(dst, total + 2); 542 if (!dst2) { 543 free(dst); 544 return NULL; 545 } else { 546 dst = dst2; 547 } 548 549 dst[total] = '\n'; 550 dst[total + 1] = '\0'; 551 return dst; 552 } 553 554 free(dst); 555 556 return NULL; 557 } 558 559 int 560 spdk_conf_read(struct spdk_conf *cp, const char *file) 561 { 562 FILE *fp; 563 char *lp, *p; 564 char *lp2, *q; 565 int line; 566 int n, n2; 567 568 if (file == NULL || file[0] == '\0') { 569 return -1; 570 } 571 572 fp = fopen(file, "r"); 573 if (fp == NULL) { 574 fprintf(stderr, "open error: %s\n", file); 575 return -1; 576 } 577 578 cp->file = strdup(file); 579 if (cp->file == NULL) { 580 perror("strdup cp->file"); 581 fclose(fp); 582 return -1; 583 } 584 585 line = 1; 586 while ((lp = fgets_line(fp)) != NULL) { 587 /* skip spaces */ 588 for (p = lp; *p != '\0' && isspace((int) *p); p++) 589 ; 590 /* skip comment, empty line */ 591 if (p[0] == '#' || p[0] == '\0') { 592 goto next_line; 593 } 594 595 /* concatenate line end with '\' */ 596 n = strlen(p); 597 while (n > 2 && p[n - 1] == '\n' && p[n - 2] == '\\') { 598 n -= 2; 599 lp2 = fgets_line(fp); 600 if (lp2 == NULL) { 601 break; 602 } 603 604 line++; 605 n2 = strlen(lp2); 606 607 q = malloc(n + n2 + 1); 608 if (!q) { 609 free(lp2); 610 free(lp); 611 fprintf(stderr, "malloc failed at line %d of %s\n", line, cp->file); 612 fclose(fp); 613 return -1; 614 } 615 616 memcpy(q, p, n); 617 memcpy(q + n, lp2, n2); 618 q[n + n2] = '\0'; 619 free(lp2); 620 free(lp); 621 p = lp = q; 622 n += n2; 623 } 624 625 /* parse one line */ 626 if (parse_line(cp, p) < 0) { 627 fprintf(stderr, "parse error at line %d of %s\n", line, cp->file); 628 } 629 next_line: 630 line++; 631 free(lp); 632 } 633 634 fclose(fp); 635 return 0; 636 } 637 638 void 639 spdk_conf_set_as_default(struct spdk_conf *cp) 640 { 641 default_config = cp; 642 } 643