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 *
spdk_conf_allocate(void)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
free_conf_value(struct spdk_conf_value * vp)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
free_all_conf_value(struct spdk_conf_value * vp)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
free_conf_item(struct spdk_conf_item * ip)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
free_all_conf_item(struct spdk_conf_item * ip)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
free_conf_section(struct spdk_conf_section * sp)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
free_all_conf_section(struct spdk_conf_section * sp)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
spdk_conf_free(struct spdk_conf * cp)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 *
allocate_cf_section(void)174 allocate_cf_section(void)
175 {
176 return calloc(1, sizeof(struct spdk_conf_section));
177 }
178
179 static struct spdk_conf_item *
allocate_cf_item(void)180 allocate_cf_item(void)
181 {
182 return calloc(1, sizeof(struct spdk_conf_item));
183 }
184
185 static struct spdk_conf_value *
allocate_cf_value(void)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 *
spdk_conf_find_section(struct spdk_conf * cp,const char * name)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 *
spdk_conf_first_section(struct spdk_conf * cp)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 *
spdk_conf_next_section(struct spdk_conf_section * sp)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
append_cf_section(struct spdk_conf * cp,struct spdk_conf_section * sp)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 *
find_cf_nitem(struct spdk_conf_section * sp,const char * key,int idx)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
append_cf_item(struct spdk_conf_section * sp,struct spdk_conf_item * ip)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
append_cf_value(struct spdk_conf_item * ip,struct spdk_conf_value * vp)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
spdk_conf_section_match_prefix(const struct spdk_conf_section * sp,const char * name_prefix)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 *
spdk_conf_section_get_name(const struct spdk_conf_section * sp)329 spdk_conf_section_get_name(const struct spdk_conf_section *sp)
330 {
331 return sp->name;
332 }
333
334 int
spdk_conf_section_get_num(const struct spdk_conf_section * sp)335 spdk_conf_section_get_num(const struct spdk_conf_section *sp)
336 {
337 return sp->num;
338 }
339
340 char *
spdk_conf_section_get_nmval(struct spdk_conf_section * sp,const char * key,int idx1,int idx2)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 *
spdk_conf_section_get_nval(struct spdk_conf_section * sp,const char * key,int idx)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 *
spdk_conf_section_get_val(struct spdk_conf_section * sp,const char * key)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
spdk_conf_section_get_intval(struct spdk_conf_section * sp,const char * key)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
spdk_conf_section_get_boolval(struct spdk_conf_section * sp,const char * key,bool default_val)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
parse_line(struct spdk_conf * cp,char * lp)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 *
fgets_line(FILE * fp)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
spdk_conf_read(struct spdk_conf * cp,const char * file)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
spdk_conf_set_as_default(struct spdk_conf * cp)670 spdk_conf_set_as_default(struct spdk_conf *cp)
671 {
672 default_config = cp;
673 }
674
675 void
spdk_conf_disable_sections_merge(struct spdk_conf * cp)676 spdk_conf_disable_sections_merge(struct spdk_conf *cp)
677 {
678 cp->merge_sections = false;
679 }
680