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