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