ucimap: add support for saving lists to uci
[project/uci.git] / ucimap.c
1 /*
2 * ucimap - library for mapping uci sections into data structures
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #include <strings.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include "ucimap.h"
24 #include "uci_internal.h"
25
26 struct uci_alloc {
27 void *ptr;
28 };
29
30 struct uci_alloc_custom {
31 void *section;
32 struct uci_optmap *om;
33 void *ptr;
34 };
35
36 struct uci_fixup {
37 struct list_head list;
38 struct uci_sectionmap *sm;
39 const char *name;
40 enum ucimap_type type;
41 union ucimap_data *data;
42 };
43
44 #define ucimap_foreach_option(_sm, _o) \
45 if (!(_sm)->options_size) \
46 (_sm)->options_size = sizeof(struct uci_optmap); \
47 for (_o = &(_sm)->options[0]; \
48 ((char *)(_o)) < ((char *) &(_sm)->options[0] + \
49 (_sm)->options_size * (_sm)->n_options); \
50 _o = (struct uci_optmap *) ((char *)(_o) + \
51 (_sm)->options_size))
52
53
54 static inline bool
55 ucimap_is_alloc(enum ucimap_type type)
56 {
57 switch(type & UCIMAP_SUBTYPE) {
58 case UCIMAP_STRING:
59 return true;
60 default:
61 return false;
62 }
63 }
64
65 static inline bool
66 ucimap_is_fixup(enum ucimap_type type)
67 {
68 switch(type & UCIMAP_SUBTYPE) {
69 case UCIMAP_SECTION:
70 return true;
71 default:
72 return false;
73 }
74 }
75
76 static inline bool
77 ucimap_is_simple(enum ucimap_type type)
78 {
79 return ((type & UCIMAP_TYPE) == UCIMAP_SIMPLE);
80 }
81
82 static inline bool
83 ucimap_is_list(enum ucimap_type type)
84 {
85 return ((type & UCIMAP_TYPE) == UCIMAP_LIST);
86 }
87
88 static inline bool
89 ucimap_is_list_auto(enum ucimap_type type)
90 {
91 return ucimap_is_list(type) && !!(type & UCIMAP_LIST_AUTO);
92 }
93
94 static inline bool
95 ucimap_is_custom(enum ucimap_type type)
96 {
97 return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM);
98 }
99
100 static inline void *
101 ucimap_section_ptr(struct ucimap_section_data *sd)
102 {
103 return ((char *) sd - sd->sm->smap_offset);
104 }
105
106 static inline struct ucimap_section_data *
107 ucimap_ptr_section(struct uci_sectionmap *sm, void *ptr) {
108 ptr = (char *) ptr + sm->smap_offset;
109 return ptr;
110 }
111
112 static inline union ucimap_data *
113 ucimap_get_data(struct ucimap_section_data *sd, struct uci_optmap *om)
114 {
115 void *data;
116
117 data = (char *) ucimap_section_ptr(sd) + om->offset;
118 return data;
119 }
120
121 int
122 ucimap_init(struct uci_map *map)
123 {
124 INIT_LIST_HEAD(&map->pending);
125 INIT_LIST_HEAD(&map->sdata);
126 INIT_LIST_HEAD(&map->fixup);
127 return 0;
128 }
129
130 static void
131 ucimap_add_alloc(struct ucimap_section_data *sd, void *ptr)
132 {
133 struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++];
134 a->ptr = ptr;
135 }
136
137 void
138 ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd)
139 {
140 void *section;
141 int i;
142
143 section = ucimap_section_ptr(sd);
144 if (!list_empty(&sd->list))
145 list_del(&sd->list);
146
147 if (sd->sm->free)
148 sd->sm->free(map, section);
149
150 for (i = 0; i < sd->allocmap_len; i++) {
151 free(sd->allocmap[i].ptr);
152 }
153
154 if (sd->alloc_custom) {
155 for (i = 0; i < sd->alloc_custom_len; i++) {
156 struct uci_alloc_custom *a = &sd->alloc_custom[i];
157 a->om->free(a->section, a->om, a->ptr);
158 }
159 free(sd->alloc_custom);
160 }
161
162 free(sd->allocmap);
163 free(sd);
164 }
165
166 void
167 ucimap_cleanup(struct uci_map *map)
168 {
169 struct list_head *ptr, *tmp;
170
171 list_for_each_safe(ptr, tmp, &map->sdata) {
172 struct ucimap_section_data *sd = list_entry(ptr, struct ucimap_section_data, list);
173 ucimap_free_section(map, sd);
174 }
175 }
176
177 static void *
178 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
179 {
180 struct ucimap_section_data *sd;
181 struct list_head *p;
182
183 list_for_each(p, &map->sdata) {
184 sd = list_entry(p, struct ucimap_section_data, list);
185 if (sd->sm != f->sm)
186 continue;
187 if (strcmp(f->name, sd->section_name) != 0)
188 continue;
189 return ucimap_section_ptr(sd);
190 }
191 list_for_each(p, &map->pending) {
192 sd = list_entry(p, struct ucimap_section_data, list);
193 if (sd->sm != f->sm)
194 continue;
195 if (strcmp(f->name, sd->section_name) != 0)
196 continue;
197 return ucimap_section_ptr(sd);
198 }
199 return NULL;
200 }
201
202 static bool
203 ucimap_handle_fixup(struct uci_map *map, struct uci_fixup *f)
204 {
205 void *ptr = ucimap_find_section(map, f);
206 struct ucimap_list *list;
207
208 if (!ptr)
209 return false;
210
211 switch(f->type & UCIMAP_TYPE) {
212 case UCIMAP_SIMPLE:
213 f->data->ptr = ptr;
214 break;
215 case UCIMAP_LIST:
216 list = f->data->list;
217 list->item[list->n_items++].ptr = ptr;
218 break;
219 }
220 return true;
221 }
222
223 void
224 ucimap_free_item(struct ucimap_section_data *sd, void *item)
225 {
226 struct uci_alloc_custom *ac;
227 struct uci_alloc *a;
228 void *ptr = *((void **) item);
229 int i;
230
231 if (!ptr)
232 return;
233
234 *((void **)item) = NULL;
235 for (i = 0, a = sd->allocmap; i < sd->allocmap_len; i++, a++) {
236 if (a->ptr != ptr)
237 continue;
238
239 if (i != sd->allocmap_len - 1)
240 a->ptr = sd->allocmap[sd->allocmap_len - 1].ptr;
241
242 sd->allocmap_len--;
243 return;
244 }
245
246 for (i = 0, ac = sd->alloc_custom; i < sd->alloc_custom_len; i++, ac++) {
247 if (ac->ptr != ptr)
248 continue;
249
250 if (i != sd->alloc_custom_len - 1)
251 memcpy(ac, &sd->alloc_custom[sd->alloc_custom_len - 1],
252 sizeof(struct uci_alloc_custom));
253
254 ac->om->free(ac->section, ac->om, ac->ptr);
255 sd->alloc_custom_len--;
256 return;
257 }
258 }
259
260 int
261 ucimap_resize_list(struct ucimap_section_data *sd, struct ucimap_list **list, int items)
262 {
263 struct ucimap_list *new;
264 struct uci_alloc *a;
265 int i, offset = 0;
266 int size = sizeof(struct ucimap_list) + items * sizeof(union ucimap_data);
267
268 if (!*list) {
269 new = calloc(1, size);
270
271 ucimap_add_alloc(sd, new);
272 goto set;
273 }
274
275 for (i = 0, a = sd->allocmap; i < sd->allocmap_len; i++, a++) {
276 if (a->ptr != *list)
277 continue;
278
279 goto realloc;
280 }
281 return -ENOENT;
282
283 realloc:
284 if (items > (*list)->size)
285 offset = (items - (*list)->size) * sizeof(union ucimap_data);
286
287 a->ptr = realloc(a->ptr, size);
288 if (offset)
289 memset((char *) a->ptr + offset, 0, size - offset);
290 new = a->ptr;
291
292 set:
293 new->size = items;
294 *list = new;
295 return 0;
296 }
297
298 static void
299 ucimap_add_fixup(struct ucimap_section_data *sd, union ucimap_data *data, struct uci_optmap *om, const char *str)
300 {
301 struct uci_fixup *f, tmp;
302 struct uci_map *map = sd->map;
303
304 INIT_LIST_HEAD(&tmp.list);
305 tmp.sm = om->data.sm;
306 tmp.name = str;
307 tmp.type = om->type;
308 tmp.data = data;
309 if (ucimap_handle_fixup(map, &tmp))
310 return;
311
312 f = malloc(sizeof(struct uci_fixup));
313 if (!f)
314 return;
315
316 memcpy(f, &tmp, sizeof(tmp));
317 list_add_tail(&f->list, &map->fixup);
318 }
319
320 static void
321 ucimap_add_custom_alloc(struct ucimap_section_data *sd, struct uci_optmap *om, void *ptr)
322 {
323 struct uci_alloc_custom *a = &sd->alloc_custom[sd->alloc_custom_len++];
324
325 a->section = ucimap_section_ptr(sd);
326 a->om = om;
327 a->ptr = ptr;
328 }
329
330 static void
331 ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str)
332 {
333 union ucimap_data tdata = *data;
334 char *eptr = NULL;
335 long lval;
336 char *s;
337 int val;
338
339 if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type)) {
340 if (unlikely(data->list->size <= data->list->n_items)) {
341 /* should not happen */
342 DPRINTF("ERROR: overflow while filling a list\n");
343 return;
344 }
345
346 data = &data->list->item[data->list->n_items++];
347 }
348
349 switch(om->type & UCIMAP_SUBTYPE) {
350 case UCIMAP_STRING:
351 if ((om->data.s.maxlen > 0) &&
352 (strlen(str) > om->data.s.maxlen))
353 return;
354
355 s = strdup(str);
356 tdata.s = s;
357 ucimap_add_alloc(sd, s);
358 break;
359 case UCIMAP_BOOL:
360 if (!strcmp(str, "on"))
361 val = true;
362 else if (!strcmp(str, "1"))
363 val = true;
364 else if (!strcmp(str, "enabled"))
365 val = true;
366 else if (!strcmp(str, "off"))
367 val = false;
368 else if (!strcmp(str, "0"))
369 val = false;
370 else if (!strcmp(str, "disabled"))
371 val = false;
372 else
373 return;
374
375 tdata.b = val;
376 break;
377 case UCIMAP_INT:
378 lval = strtol(str, &eptr, om->data.i.base);
379 if (lval < INT_MIN || lval > INT_MAX)
380 return;
381
382 if (!eptr || *eptr == '\0')
383 tdata.i = (int) lval;
384 else
385 return;
386 break;
387 case UCIMAP_SECTION:
388 ucimap_add_fixup(sd, data, om, str);
389 return;
390 case UCIMAP_CUSTOM:
391 tdata.s = (char *) data;
392 break;
393 }
394 if (om->parse) {
395 if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0)
396 return;
397 if (ucimap_is_custom(om->type) && om->free) {
398 if (tdata.ptr != data->ptr)
399 ucimap_add_custom_alloc(sd, om, data->ptr);
400 }
401 }
402 if (ucimap_is_custom(om->type))
403 return;
404 memcpy(data, &tdata, sizeof(union ucimap_data));
405 }
406
407
408 static void
409 ucimap_convert_list(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str)
410 {
411 char *s, *p;
412
413 s = strdup(str);
414 if (!s)
415 return;
416
417 ucimap_add_alloc(sd, s);
418
419 do {
420 while (isspace(*s))
421 s++;
422
423 if (!*s)
424 break;
425
426 p = s;
427 while (*s && !isspace(*s))
428 s++;
429
430 if (isspace(*s)) {
431 *s = 0;
432 s++;
433 }
434
435 ucimap_add_value(data, om, sd, p);
436 } while (*s);
437 }
438
439 static int
440 ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s)
441 {
442 struct uci_element *e, *l;
443 struct uci_option *o;
444 union ucimap_data *data;
445
446 uci_foreach_element(&s->options, e) {
447 struct uci_optmap *om = NULL, *tmp;
448
449 ucimap_foreach_option(sm, tmp) {
450 if (strcmp(e->name, tmp->name) == 0) {
451 om = tmp;
452 break;
453 }
454 }
455 if (!om)
456 continue;
457
458 data = ucimap_get_data(sd, om);
459 o = uci_to_option(e);
460 if ((o->type == UCI_TYPE_STRING) && ucimap_is_simple(om->type)) {
461 ucimap_add_value(data, om, sd, o->v.string);
462 } else if ((o->type == UCI_TYPE_LIST) && ucimap_is_list(om->type)) {
463 uci_foreach_element(&o->v.list, l) {
464 ucimap_add_value(data, om, sd, l->name);
465 }
466 } else if ((o->type == UCI_TYPE_STRING) && ucimap_is_list_auto(om->type)) {
467 ucimap_convert_list(data, om, sd, o->v.string);
468 }
469 }
470
471 return 0;
472 }
473
474 static void
475 ucimap_add_section(struct ucimap_section_data *sd)
476 {
477 struct uci_map *map = sd->map;
478
479 if (sd->sm->add(map, ucimap_section_ptr(sd)) < 0)
480 ucimap_free_section(map, sd);
481 else
482 list_add_tail(&sd->list, &map->sdata);
483 }
484
485 static const char *ucimap_type_names[] = {
486 [UCIMAP_STRING] = "string",
487 [UCIMAP_INT] = "integer",
488 [UCIMAP_BOOL] = "boolean",
489 [UCIMAP_SECTION] = "section",
490 [UCIMAP_LIST] = "list",
491 };
492
493 static inline const char *
494 ucimap_get_type_name(int type)
495 {
496 static char buf[32];
497 const char *name;
498
499 if (ucimap_is_list(type))
500 return ucimap_type_names[UCIMAP_LIST];
501
502 name = ucimap_type_names[type & UCIMAP_SUBTYPE];
503 if (!name) {
504 sprintf(buf, "Unknown (%d)", type & UCIMAP_SUBTYPE);
505 name = buf;
506 }
507
508 return name;
509 }
510
511 static bool
512 ucimap_check_optmap_type(struct uci_sectionmap *sm, struct uci_optmap *om)
513 {
514 unsigned int type;
515
516 if (unlikely(sm->type_name != om->type_name) &&
517 unlikely(strcmp(sm->type_name, om->type_name) != 0)) {
518 DPRINTF("Option '%s' of section type '%s' refereces unknown "
519 "section type '%s', should be '%s'.\n",
520 om->name, sm->type, om->type_name, sm->type_name);
521 return false;
522 }
523
524 if (om->detected_type < 0)
525 return true;
526
527 if (ucimap_is_custom(om->type))
528 return true;
529
530 if (ucimap_is_list(om->type) !=
531 ucimap_is_list(om->detected_type))
532 goto failed;
533
534 if (ucimap_is_list(om->type))
535 return true;
536
537 type = om->type & UCIMAP_SUBTYPE;
538 switch(type) {
539 case UCIMAP_STRING:
540 case UCIMAP_INT:
541 case UCIMAP_BOOL:
542 if (type != om->detected_type)
543 goto failed;
544 break;
545 case UCIMAP_SECTION:
546 goto failed;
547 default:
548 break;
549 }
550 return true;
551
552 failed:
553 DPRINTF("Invalid type in option '%s' of section type '%s', "
554 "declared type is %s, detected type is %s\n",
555 om->name, sm->type,
556 ucimap_get_type_name(om->type),
557 ucimap_get_type_name(om->detected_type));
558 return false;
559 }
560
561 static void
562 ucimap_count_alloc(struct uci_optmap *om, int *n_alloc, int *n_custom)
563 {
564 if (ucimap_is_alloc(om->type))
565 (*n_alloc)++;
566 else if (ucimap_is_custom(om->type) && om->free)
567 (*n_custom)++;
568 }
569
570 int
571 ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s)
572 {
573 struct uci_optmap *om;
574 char *section_name;
575 void *section;
576 int n_alloc = 2;
577 int n_alloc_custom = 0;
578 int err;
579
580 INIT_LIST_HEAD(&sd->list);
581 sd->map = map;
582 sd->sm = sm;
583
584 ucimap_foreach_option(sm, om) {
585 if (!ucimap_check_optmap_type(sm, om))
586 continue;
587
588 if (ucimap_is_list(om->type)) {
589 union ucimap_data *data;
590 struct uci_element *e;
591 int n_elements = 0;
592 int n_elements_custom = 0;
593 int size;
594
595 data = ucimap_get_data(sd, om);
596 uci_foreach_element(&s->options, e) {
597 struct uci_option *o = uci_to_option(e);
598 struct uci_element *tmp;
599
600 if (strcmp(e->name, om->name) != 0)
601 continue;
602
603 if (o->type == UCI_TYPE_LIST) {
604 uci_foreach_element(&o->v.list, tmp) {
605 ucimap_count_alloc(om, &n_elements, &n_elements_custom);
606 }
607 } else if ((o->type == UCI_TYPE_STRING) &&
608 ucimap_is_list_auto(om->type)) {
609 const char *data = o->v.string;
610 do {
611 while (isspace(*data))
612 data++;
613
614 if (!*data)
615 break;
616
617 n_elements++;
618 ucimap_count_alloc(om, &n_elements, &n_elements_custom);
619
620 while (*data && !isspace(*data))
621 data++;
622 } while (*data);
623
624 /* for the duplicated data string */
625 if (n_elements)
626 n_alloc++;
627 }
628 break;
629 }
630 /* add one more for the ucimap_list */
631 n_alloc += n_elements + 1;
632 n_alloc_custom += n_elements_custom;
633 size = sizeof(struct ucimap_list) +
634 n_elements * sizeof(union ucimap_data);
635
636 data->list = malloc(size);
637 if (!data->list)
638 goto error_mem;
639
640 data->list->size = n_elements;
641 memset(data->list, 0, size);
642 } else {
643 ucimap_count_alloc(om, &n_alloc, &n_alloc_custom);
644 }
645 }
646
647 sd->allocmap = calloc(n_alloc, sizeof(struct uci_alloc));
648 if (!sd->allocmap)
649 goto error_mem;
650
651 if (n_alloc_custom > 0) {
652 sd->alloc_custom = calloc(n_alloc_custom, sizeof(struct uci_alloc_custom));
653 if (!sd->alloc_custom)
654 goto error_mem;
655 }
656
657 section_name = strdup(s->e.name);
658 if (!section_name)
659 goto error_mem;
660
661 sd->section_name = section_name;
662
663 sd->cmap = calloc(1, BITFIELD_SIZE(sm->n_options));
664 if (!sd->cmap)
665 goto error_mem;
666
667 ucimap_add_alloc(sd, (void *)section_name);
668 ucimap_add_alloc(sd, (void *)sd->cmap);
669 ucimap_foreach_option(sm, om) {
670 if (!ucimap_is_list(om->type))
671 continue;
672
673 ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list);
674 }
675
676 section = ucimap_section_ptr(sd);
677 err = sm->init(map, section, s);
678 if (err)
679 goto error;
680
681 if (map->parsed) {
682 ucimap_add_section(sd);
683 } else {
684 list_add_tail(&sd->list, &map->pending);
685 }
686
687 err = ucimap_parse_options(map, sm, sd, s);
688 if (err)
689 goto error;
690
691 return 0;
692
693 error_mem:
694 if (sd->allocmap)
695 free(sd->allocmap);
696 free(sd);
697 return UCI_ERR_MEM;
698
699 error:
700 ucimap_free_section(map, sd);
701 return err;
702 }
703
704 static int
705 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
706 {
707 struct uci_package *p = s->package;
708
709 memset(ptr, 0, sizeof(struct uci_ptr));
710
711 ptr->package = p->e.name;
712 ptr->p = p;
713
714 ptr->section = s->e.name;
715 ptr->s = s;
716
717 ptr->option = option;
718 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
719 }
720
721 void
722 ucimap_set_changed(struct ucimap_section_data *sd, void *field)
723 {
724 void *section = ucimap_section_ptr(sd);
725 struct uci_sectionmap *sm = sd->sm;
726 struct uci_optmap *om;
727 int ofs = (char *)field - (char *)section;
728 int i = 0;
729
730 ucimap_foreach_option(sm, om) {
731 if (om->offset == ofs) {
732 SET_BIT(sd->cmap, i);
733 break;
734 }
735 i++;
736 }
737 }
738
739 static char *
740 ucimap_data_to_string(struct ucimap_section_data *sd, struct uci_optmap *om, union ucimap_data *data)
741 {
742 static char buf[32];
743 char *str = NULL;
744
745 switch(om->type & UCIMAP_SUBTYPE) {
746 case UCIMAP_STRING:
747 str = data->s;
748 break;
749 case UCIMAP_INT:
750 sprintf(buf, "%d", data->i);
751 str = buf;
752 break;
753 case UCIMAP_BOOL:
754 sprintf(buf, "%d", !!data->b);
755 str = buf;
756 break;
757 case UCIMAP_SECTION:
758 if (data->ptr)
759 str = (char *) ucimap_ptr_section(om->data.sm, data->ptr)->section_name;
760 else
761 str = "";
762 break;
763 case UCIMAP_CUSTOM:
764 break;
765 default:
766 return NULL;
767 }
768
769 if (om->format) {
770 union ucimap_data tdata;
771
772 if (ucimap_is_custom(om->type)) {
773 tdata.s = (char *)data;
774 data = &tdata;
775 }
776
777 if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
778 return NULL;
779
780 if (!str)
781 str = "";
782 }
783 return str;
784 }
785
786 int
787 ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd)
788 {
789 struct uci_sectionmap *sm = sd->sm;
790 struct uci_section *s = NULL;
791 struct uci_optmap *om;
792 struct uci_element *e;
793 struct uci_ptr ptr;
794 int i = 0;
795 int ret;
796
797 uci_foreach_element(&p->sections, e) {
798 if (!strcmp(e->name, sd->section_name)) {
799 s = uci_to_section(e);
800 break;
801 }
802 }
803 if (!s)
804 return UCI_ERR_NOTFOUND;
805
806 ucimap_foreach_option(sm, om) {
807 union ucimap_data *data;
808
809 i++;
810 data = ucimap_get_data(sd, om);
811 if (!TEST_BIT(sd->cmap, i - 1))
812 continue;
813
814 ucimap_fill_ptr(&ptr, s, om->name);
815 if (ucimap_is_list(om->type)) {
816 struct ucimap_list *list = data->list;
817 bool first = true;
818 int j;
819
820 for (j = 0; j < list->n_items; j++) {
821 ptr.value = ucimap_data_to_string(sd, om, &list->item[j]);
822 if (!ptr.value)
823 continue;
824
825 if (first) {
826 ret = uci_set(s->package->ctx, &ptr);
827 first = false;
828 } else {
829 ret = uci_add_list(s->package->ctx, &ptr);
830 }
831 if (ret)
832 return ret;
833 }
834 } else {
835 ptr.value = ucimap_data_to_string(sd, om, data);
836 if (!ptr.value)
837 continue;
838
839 ret = uci_set(s->package->ctx, &ptr);
840 if (ret)
841 return ret;
842 }
843
844 CLR_BIT(sd->cmap, i - 1);
845 }
846
847 return 0;
848 }
849
850 void
851 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
852 {
853 struct uci_element *e;
854 struct list_head *p, *tmp;
855 int i;
856
857 INIT_LIST_HEAD(&map->fixup);
858 uci_foreach_element(&pkg->sections, e) {
859 struct uci_section *s = uci_to_section(e);
860
861 for (i = 0; i < map->n_sections; i++) {
862 struct uci_sectionmap *sm = map->sections[i];
863 struct ucimap_section_data *sd;
864
865 if (strcmp(s->type, map->sections[i]->type) != 0)
866 continue;
867
868 if (sm->alloc) {
869 sd = sm->alloc(map, sm, s);
870 memset(sd, 0, sizeof(struct ucimap_section_data));
871 } else {
872 sd = malloc(sm->alloc_len);
873 memset(sd, 0, sm->alloc_len);
874 }
875 if (!sd)
876 continue;
877
878 ucimap_parse_section(map, sm, sd, s);
879 }
880 }
881 map->parsed = true;
882
883 list_for_each_safe(p, tmp, &map->fixup) {
884 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
885 ucimap_handle_fixup(map, f);
886 list_del(&f->list);
887 free(f);
888 }
889
890 list_for_each_safe(p, tmp, &map->pending) {
891 struct ucimap_section_data *sd;
892 sd = list_entry(p, struct ucimap_section_data, list);
893
894 list_del_init(&sd->list);
895 ucimap_add_section(sd);
896 }
897 }