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 0 : spdk_conf_allocate(void)
47 : {
48 0 : struct spdk_conf *ret = calloc(1, sizeof(struct spdk_conf));
49 :
50 0 : if (ret) {
51 0 : ret->merge_sections = true;
52 0 : }
53 :
54 0 : return ret;
55 : }
56 :
57 : static void
58 0 : free_conf_value(struct spdk_conf_value *vp)
59 : {
60 0 : if (vp == NULL) {
61 0 : return;
62 : }
63 :
64 0 : if (vp->value) {
65 0 : free(vp->value);
66 0 : }
67 :
68 0 : free(vp);
69 0 : }
70 :
71 : static void
72 0 : free_all_conf_value(struct spdk_conf_value *vp)
73 : {
74 : struct spdk_conf_value *next;
75 :
76 0 : if (vp == NULL) {
77 0 : return;
78 : }
79 :
80 0 : while (vp != NULL) {
81 0 : next = vp->next;
82 0 : free_conf_value(vp);
83 0 : vp = next;
84 : }
85 0 : }
86 :
87 : static void
88 0 : free_conf_item(struct spdk_conf_item *ip)
89 : {
90 0 : if (ip == NULL) {
91 0 : return;
92 : }
93 :
94 0 : if (ip->val != NULL) {
95 0 : free_all_conf_value(ip->val);
96 0 : }
97 :
98 0 : if (ip->key != NULL) {
99 0 : free(ip->key);
100 0 : }
101 :
102 0 : free(ip);
103 0 : }
104 :
105 : static void
106 0 : free_all_conf_item(struct spdk_conf_item *ip)
107 : {
108 : struct spdk_conf_item *next;
109 :
110 0 : if (ip == NULL) {
111 0 : return;
112 : }
113 :
114 0 : while (ip != NULL) {
115 0 : next = ip->next;
116 0 : free_conf_item(ip);
117 0 : ip = next;
118 : }
119 0 : }
120 :
121 : static void
122 0 : free_conf_section(struct spdk_conf_section *sp)
123 : {
124 0 : if (sp == NULL) {
125 0 : return;
126 : }
127 :
128 0 : if (sp->item) {
129 0 : free_all_conf_item(sp->item);
130 0 : }
131 :
132 0 : if (sp->name) {
133 0 : free(sp->name);
134 0 : }
135 :
136 0 : free(sp);
137 0 : }
138 :
139 : static void
140 0 : free_all_conf_section(struct spdk_conf_section *sp)
141 : {
142 : struct spdk_conf_section *next;
143 :
144 0 : if (sp == NULL) {
145 0 : return;
146 : }
147 :
148 0 : while (sp != NULL) {
149 0 : next = sp->next;
150 0 : free_conf_section(sp);
151 0 : sp = next;
152 : }
153 0 : }
154 :
155 : void
156 0 : spdk_conf_free(struct spdk_conf *cp)
157 : {
158 0 : if (cp == NULL) {
159 0 : return;
160 : }
161 :
162 0 : if (cp->section != NULL) {
163 0 : free_all_conf_section(cp->section);
164 0 : }
165 :
166 0 : if (cp->file != NULL) {
167 0 : free(cp->file);
168 0 : }
169 :
170 0 : free(cp);
171 0 : }
172 :
173 : static struct spdk_conf_section *
174 0 : allocate_cf_section(void)
175 : {
176 0 : return calloc(1, sizeof(struct spdk_conf_section));
177 : }
178 :
179 : static struct spdk_conf_item *
180 0 : allocate_cf_item(void)
181 : {
182 0 : return calloc(1, sizeof(struct spdk_conf_item));
183 : }
184 :
185 : static struct spdk_conf_value *
186 0 : allocate_cf_value(void)
187 : {
188 0 : 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 0 : }
214 :
215 0 : return NULL;
216 0 : }
217 :
218 : struct spdk_conf_section *
219 0 : spdk_conf_first_section(struct spdk_conf *cp)
220 : {
221 0 : cp = CHECK_CP_OR_USE_DEFAULT(cp);
222 0 : if (cp == NULL) {
223 0 : return NULL;
224 : }
225 :
226 0 : return cp->section;
227 0 : }
228 :
229 : struct spdk_conf_section *
230 0 : spdk_conf_next_section(struct spdk_conf_section *sp)
231 : {
232 0 : if (sp == NULL) {
233 0 : return NULL;
234 : }
235 :
236 0 : return sp->next;
237 0 : }
238 :
239 : static void
240 0 : append_cf_section(struct spdk_conf *cp, struct spdk_conf_section *sp)
241 : {
242 : struct spdk_conf_section *last;
243 :
244 0 : cp = CHECK_CP_OR_USE_DEFAULT(cp);
245 0 : if (cp == NULL) {
246 0 : SPDK_ERRLOG("cp == NULL\n");
247 0 : return;
248 : }
249 :
250 0 : if (cp->section == NULL) {
251 0 : cp->section = sp;
252 0 : return;
253 : }
254 :
255 0 : for (last = cp->section; last->next != NULL; last = last->next)
256 : ;
257 0 : last->next = sp;
258 0 : }
259 :
260 : static struct spdk_conf_item *
261 0 : 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 0 : if (key == NULL || key[0] == '\0') {
267 0 : return NULL;
268 : }
269 :
270 0 : i = 0;
271 0 : for (ip = sp->item; ip != NULL; ip = ip->next) {
272 0 : if (ip->key != NULL && ip->key[0] == key[0]
273 0 : && strcasecmp(ip->key, key) == 0) {
274 0 : if (i == idx) {
275 0 : return ip;
276 : }
277 0 : i++;
278 0 : }
279 0 : }
280 :
281 0 : return NULL;
282 0 : }
283 :
284 : static void
285 0 : append_cf_item(struct spdk_conf_section *sp, struct spdk_conf_item *ip)
286 : {
287 : struct spdk_conf_item *last;
288 :
289 0 : if (sp == NULL) {
290 0 : return;
291 : }
292 :
293 0 : if (sp->item == NULL) {
294 0 : sp->item = ip;
295 0 : return;
296 : }
297 :
298 0 : for (last = sp->item; last->next != NULL; last = last->next)
299 : ;
300 0 : last->next = ip;
301 0 : }
302 :
303 : static void
304 0 : append_cf_value(struct spdk_conf_item *ip, struct spdk_conf_value *vp)
305 : {
306 : struct spdk_conf_value *last;
307 :
308 0 : if (ip == NULL) {
309 0 : return;
310 : }
311 :
312 0 : if (ip->val == NULL) {
313 0 : ip->val = vp;
314 0 : return;
315 : }
316 :
317 0 : for (last = ip->val; last->next != NULL; last = last->next)
318 : ;
319 0 : last->next = vp;
320 0 : }
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 0 : spdk_conf_section_get_name(const struct spdk_conf_section *sp)
330 : {
331 0 : 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 0 : }
362 :
363 0 : return NULL;
364 0 : }
365 :
366 : char *
367 0 : 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 0 : ip = find_cf_nitem(sp, key, idx);
373 0 : if (ip == NULL) {
374 0 : return NULL;
375 : }
376 :
377 0 : vp = ip->val;
378 0 : if (vp == NULL) {
379 0 : return NULL;
380 : }
381 :
382 0 : return vp->value;
383 0 : }
384 :
385 : char *
386 0 : spdk_conf_section_get_val(struct spdk_conf_section *sp, const char *key)
387 : {
388 0 : return spdk_conf_section_get_nval(sp, key, 0);
389 : }
390 :
391 : int
392 0 : spdk_conf_section_get_intval(struct spdk_conf_section *sp, const char *key)
393 : {
394 : const char *v;
395 : int value;
396 :
397 0 : v = spdk_conf_section_get_nval(sp, key, 0);
398 0 : if (v == NULL) {
399 0 : return -1;
400 : }
401 :
402 0 : value = (int)spdk_strtol(v, 10);
403 0 : return value;
404 0 : }
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 0 : }
426 :
427 : static int
428 0 : 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 0 : arg = spdk_str_trim(lp);
440 0 : if (arg == NULL) {
441 0 : SPDK_ERRLOG("no section\n");
442 0 : return -1;
443 : }
444 :
445 0 : if (arg[0] == '[') {
446 : /* section */
447 0 : arg++;
448 0 : key = spdk_strsepq(&arg, "]");
449 0 : if (key == NULL || arg != NULL) {
450 0 : SPDK_ERRLOG("broken section\n");
451 0 : return -1;
452 : }
453 : /* determine section number */
454 0 : for (p = key; *p != '\0' && !isdigit((int) *p); p++)
455 : ;
456 0 : if (*p != '\0') {
457 0 : num = (int)spdk_strtol(p, 10);
458 0 : } else {
459 0 : num = 0;
460 : }
461 :
462 0 : if (cp->merge_sections) {
463 0 : sp = spdk_conf_find_section(cp, key);
464 0 : } else {
465 0 : sp = NULL;
466 : }
467 :
468 0 : if (sp == NULL) {
469 0 : sp = allocate_cf_section();
470 0 : if (sp == NULL) {
471 0 : SPDK_ERRLOG("cannot allocate cf section\n");
472 0 : return -1;
473 : }
474 0 : append_cf_section(cp, sp);
475 :
476 0 : sp->name = strdup(key);
477 0 : if (sp->name == NULL) {
478 0 : SPDK_ERRLOG("cannot duplicate %s to sp->name\n", key);
479 0 : return -1;
480 : }
481 0 : }
482 0 : cp->current_section = sp;
483 :
484 :
485 0 : sp->num = num;
486 0 : } else {
487 : /* parameters */
488 0 : sp = cp->current_section;
489 0 : if (sp == NULL) {
490 0 : SPDK_ERRLOG("unknown section\n");
491 0 : return -1;
492 : }
493 0 : key = spdk_strsepq(&arg, CF_DELIM_KEY);
494 0 : if (key == NULL) {
495 0 : SPDK_ERRLOG("broken key\n");
496 0 : return -1;
497 : }
498 :
499 0 : ip = allocate_cf_item();
500 0 : if (ip == NULL) {
501 0 : SPDK_ERRLOG("cannot allocate cf item\n");
502 0 : return -1;
503 : }
504 0 : append_cf_item(sp, ip);
505 0 : ip->key = strdup(key);
506 0 : if (ip->key == NULL) {
507 0 : SPDK_ERRLOG("cannot make duplicate of %s\n", key);
508 0 : return -1;
509 : }
510 0 : ip->val = NULL;
511 0 : if (arg != NULL) {
512 : /* key has value(s) */
513 0 : while (arg != NULL) {
514 0 : val = spdk_strsepq(&arg, CF_DELIM);
515 0 : vp = allocate_cf_value();
516 0 : if (vp == NULL) {
517 0 : SPDK_ERRLOG("cannot allocate cf value\n");
518 0 : return -1;
519 : }
520 0 : append_cf_value(ip, vp);
521 0 : vp->value = strdup(val);
522 0 : if (vp->value == NULL) {
523 0 : SPDK_ERRLOG("cannot duplicate %s to vp->value\n", val);
524 0 : return -1;
525 : }
526 : }
527 0 : }
528 : }
529 :
530 0 : return 0;
531 0 : }
532 :
533 : static char *
534 0 : fgets_line(FILE *fp)
535 : {
536 : char *dst, *dst2, *p;
537 : size_t total, len;
538 :
539 0 : dst = p = malloc(LIB_MAX_TMPBUF);
540 0 : if (!dst) {
541 0 : return NULL;
542 : }
543 :
544 0 : dst[0] = '\0';
545 0 : total = 0;
546 :
547 0 : while (fgets(p, LIB_MAX_TMPBUF, fp) != NULL) {
548 0 : len = strlen(p);
549 0 : total += len;
550 0 : if (len + 1 < LIB_MAX_TMPBUF || dst[total - 1] == '\n') {
551 0 : dst2 = realloc(dst, total + 1);
552 0 : if (!dst2) {
553 0 : free(dst);
554 0 : return NULL;
555 : } else {
556 0 : 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 0 : 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 0 : free(dst);
586 :
587 0 : return NULL;
588 0 : }
589 :
590 : int
591 0 : 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 0 : if (file == NULL || file[0] == '\0') {
600 0 : return -1;
601 : }
602 :
603 0 : fp = fopen(file, "r");
604 0 : if (fp == NULL) {
605 0 : SPDK_ERRLOG("open error: %s\n", file);
606 0 : return -1;
607 : }
608 :
609 0 : cp->file = strdup(file);
610 0 : 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 0 : line = 1;
617 0 : while ((lp = fgets_line(fp)) != NULL) {
618 : /* skip spaces */
619 0 : for (p = lp; *p != '\0' && isspace((int) *p); p++)
620 : ;
621 : /* skip comment, empty line */
622 0 : if (p[0] == '#' || p[0] == '\0') {
623 0 : goto next_line;
624 : }
625 :
626 : /* concatenate line end with '\' */
627 0 : n = strlen(p);
628 0 : 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 0 : if (parse_line(cp, p) < 0) {
658 0 : SPDK_ERRLOG("parse error at line %d of %s\n", line, cp->file);
659 0 : }
660 : next_line:
661 0 : line++;
662 0 : free(lp);
663 : }
664 :
665 0 : fclose(fp);
666 0 : return 0;
667 0 : }
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 0 : spdk_conf_disable_sections_merge(struct spdk_conf *cp)
677 : {
678 0 : cp->merge_sections = false;
679 0 : }
|