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