191c97c4b9153df2ab589c8fcaf68bcbecbb3021
2 * ucimap - library for mapping uci sections into data structures
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
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
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.
22 enum ucimap_type type
;
29 struct list_head list
;
30 struct uci_sectmap
*sm
;
32 enum ucimap_type type
;
33 union ucimap_data
*data
;
36 struct uci_sectmap_data
{
37 struct list_head list
;
39 struct uci_sectmap
*sm
;
40 const char *section_name
;
42 /* list of allocations done by ucimap */
43 struct uci_alloc
*allocmap
;
44 unsigned long allocmap_len
;
46 /* map for changed fields */
52 #define ucimap_foreach_option(_sm, _o) \
53 if (!(_sm)->options_size) \
54 (_sm)->options_size = sizeof(struct uci_optmap); \
55 for (_o = &(_sm)->options[0]; \
56 ((char *)(_o)) < ((char *) &(_sm)->options[0] + \
57 (_sm)->options_size * (_sm)->n_options); \
58 _o = (struct uci_optmap *) ((char *)(_o) + \
63 ucimap_is_alloc(enum ucimap_type type
)
65 switch(type
& UCIMAP_SUBTYPE
) {
74 ucimap_is_fixup(enum ucimap_type type
)
76 switch(type
& UCIMAP_SUBTYPE
) {
85 ucimap_is_simple(enum ucimap_type type
)
87 return ((type
& UCIMAP_TYPE
) == UCIMAP_SIMPLE
);
91 ucimap_is_list(enum ucimap_type type
)
93 return ((type
& UCIMAP_TYPE
) == UCIMAP_LIST
);
96 static inline union ucimap_data
*
97 ucimap_get_data(struct uci_sectmap_data
*sd
, struct uci_optmap
*om
)
101 data
= (char *) sd
+ sizeof(struct uci_sectmap_data
) + om
->offset
;
106 ucimap_init(struct uci_map
*map
)
108 INIT_LIST_HEAD(&map
->sdata
);
109 INIT_LIST_HEAD(&map
->fixup
);
114 ucimap_free_item(struct uci_alloc
*a
)
116 switch(a
->type
& UCIMAP_TYPE
) {
125 ucimap_add_alloc(struct uci_sectmap_data
*sd
, void *ptr
)
127 struct uci_alloc
*a
= &sd
->allocmap
[sd
->allocmap_len
++];
128 a
->type
= UCIMAP_SIMPLE
;
133 ucimap_free_section(struct uci_map
*map
, struct uci_sectmap_data
*sd
)
138 section
= (char *) section
+ sizeof(struct uci_sectmap_data
);
139 if (!list_empty(&sd
->list
))
143 sd
->sm
->free(map
, section
);
145 for (i
= 0; i
< sd
->allocmap_len
; i
++) {
146 ucimap_free_item(&sd
->allocmap
[i
]);
154 ucimap_cleanup(struct uci_map
*map
)
156 struct list_head
*ptr
, *tmp
;
158 list_for_each_safe(ptr
, tmp
, &map
->sdata
) {
159 struct uci_sectmap_data
*sd
= list_entry(ptr
, struct uci_sectmap_data
, list
);
160 ucimap_free_section(map
, sd
);
165 ucimap_add_fixup(struct uci_map
*map
, union ucimap_data
*data
, struct uci_optmap
*om
, const char *str
)
169 f
= malloc(sizeof(struct uci_fixup
));
173 INIT_LIST_HEAD(&f
->list
);
178 list_add(&f
->list
, &map
->fixup
);
182 ucimap_add_value(union ucimap_data
*data
, struct uci_optmap
*om
, struct uci_sectmap_data
*sd
, const char *str
)
184 union ucimap_data
*tdata
= data
;
189 if (ucimap_is_list(om
->type
) && !ucimap_is_fixup(om
->type
))
190 tdata
= &data
->list
->item
[data
->list
->n_items
++];
192 switch(om
->type
& UCIMAP_SUBTYPE
) {
194 if ((om
->data
.s
.maxlen
> 0) &&
195 (strlen(str
) > om
->data
.s
.maxlen
))
200 ucimap_add_alloc(sd
, s
);
204 if (strcmp(str
, "on"))
206 else if (strcmp(str
, "1"))
208 else if (strcmp(str
, "enabled"))
210 else if (strcmp(str
, "off"))
212 else if (strcmp(str
, "0"))
214 else if (strcmp(str
, "disabled"))
222 val
= strtol(str
, &eptr
, om
->data
.i
.base
);
223 if (!eptr
|| *eptr
== '\0')
229 ucimap_add_fixup(sd
->map
, data
, om
, str
);
236 ucimap_parse_options(struct uci_map
*map
, struct uci_sectmap
*sm
, struct uci_sectmap_data
*sd
, struct uci_section
*s
)
238 struct uci_element
*e
, *l
;
239 struct uci_option
*o
;
240 union ucimap_data
*data
;
242 uci_foreach_element(&s
->options
, e
) {
243 struct uci_optmap
*om
= NULL
, *tmp
;
245 ucimap_foreach_option(sm
, tmp
) {
246 if (strcmp(e
->name
, tmp
->name
) == 0) {
254 data
= ucimap_get_data(sd
, om
);
255 o
= uci_to_option(e
);
256 if ((o
->type
== UCI_TYPE_STRING
) && ucimap_is_simple(om
->type
)) {
257 ucimap_add_value(data
, om
, sd
, o
->v
.string
);
258 } else if ((o
->type
== UCI_TYPE_LIST
) && ucimap_is_list(om
->type
)) {
259 uci_foreach_element(&o
->v
.list
, l
) {
260 ucimap_add_value(data
, om
, sd
, l
->name
);
270 ucimap_parse_section(struct uci_map
*map
, struct uci_sectmap
*sm
, struct uci_section
*s
)
272 struct uci_sectmap_data
*sd
= NULL
;
273 struct uci_optmap
*om
;
279 sd
= malloc(sm
->alloc_len
+ sizeof(struct uci_sectmap_data
));
283 memset(sd
, 0, sm
->alloc_len
+ sizeof(struct uci_sectmap_data
));
284 INIT_LIST_HEAD(&sd
->list
);
286 ucimap_foreach_option(sm
, om
) {
287 if (ucimap_is_list(om
->type
)) {
288 union ucimap_data
*data
;
289 struct uci_element
*e
;
293 data
= ucimap_get_data(sd
, om
);
294 uci_foreach_element(&s
->options
, e
) {
295 struct uci_option
*o
= uci_to_option(e
);
296 struct uci_element
*tmp
;
298 if (strcmp(e
->name
, om
->name
) != 0)
301 uci_foreach_element(&o
->v
.list
, tmp
) {
306 n_alloc
+= n_elements
+ 1;
307 size
= sizeof(struct ucimap_list
) +
308 n_elements
* sizeof(union ucimap_data
);
309 data
->list
= malloc(size
);
310 memset(data
->list
, 0, size
);
311 } else if (ucimap_is_alloc(om
->type
)) {
318 sd
->allocmap
= malloc(n_alloc
* sizeof(struct uci_alloc
));
322 section_name
= strdup(s
->e
.name
);
326 sd
->section_name
= section_name
;
328 sd
->cmap
= malloc(BITFIELD_SIZE(sm
->n_options
));
332 memset(sd
->cmap
, 0, BITFIELD_SIZE(sm
->n_options
));
333 ucimap_add_alloc(sd
, (void *)section_name
);
334 ucimap_add_alloc(sd
, (void *)sd
->cmap
);
335 ucimap_foreach_option(sm
, om
) {
336 if (!ucimap_is_list(om
->type
))
339 ucimap_add_alloc(sd
, ucimap_get_data(sd
, om
)->list
);
342 section
= (char *)sd
+ sizeof(struct uci_sectmap_data
);
344 err
= sm
->init(map
, section
, s
);
348 list_add(&sd
->list
, &map
->sdata
);
349 err
= ucimap_parse_options(map
, sm
, sd
, s
);
362 ucimap_free_section(map
, sd
);
367 ucimap_fill_ptr(struct uci_ptr
*ptr
, struct uci_section
*s
, const char *option
)
369 struct uci_package
*p
= s
->package
;
371 memset(ptr
, 0, sizeof(struct uci_ptr
));
373 ptr
->package
= p
->e
.name
;
376 ptr
->section
= s
->e
.name
;
379 ptr
->option
= option
;
380 return uci_lookup_ptr(p
->ctx
, ptr
, NULL
, false);
384 ucimap_set_changed(void *section
, void *field
)
386 char *sptr
= (char *)section
- sizeof(struct uci_sectmap_data
);
387 struct uci_sectmap_data
*sd
= (struct uci_sectmap_data
*) sptr
;
388 struct uci_sectmap
*sm
= sd
->sm
;
389 struct uci_optmap
*om
;
390 int ofs
= (char *)field
- (char *)section
;
393 ucimap_foreach_option(sm
, om
) {
394 if (om
->offset
== ofs
) {
395 SET_BIT(sd
->cmap
, i
);
403 ucimap_store_section(struct uci_map
*map
, struct uci_package
*p
, void *section
)
405 char *sptr
= (char *)section
- sizeof(struct uci_sectmap_data
);
406 struct uci_sectmap_data
*sd
= (struct uci_sectmap_data
*) sptr
;
407 struct uci_sectmap
*sm
= sd
->sm
;
408 struct uci_section
*s
= NULL
;
409 struct uci_optmap
*om
;
410 struct uci_element
*e
;
415 uci_foreach_element(&p
->sections
, e
) {
416 if (!strcmp(e
->name
, sd
->section_name
)) {
417 s
= uci_to_section(e
);
422 return UCI_ERR_NOTFOUND
;
424 ucimap_foreach_option(sm
, om
) {
425 union ucimap_data
*data
;
427 const char *str
= NULL
;
429 if (ucimap_is_list(om
->type
))
432 data
= ucimap_get_data(sd
, om
);
433 if (!TEST_BIT(sd
->cmap
, i
))
436 ucimap_fill_ptr(&ptr
, s
, om
->name
);
437 switch(om
->type
& UCIMAP_SUBTYPE
) {
442 sprintf(buf
, "%d", data
->i
);
446 sprintf(buf
, "%d", !!data
->b
);
454 ret
= uci_set(s
->package
->ctx
, &ptr
);
458 CLR_BIT(sd
->cmap
, i
);
466 ucimap_find_section(struct uci_map
*map
, struct uci_fixup
*f
)
468 struct uci_sectmap_data
*sd
;
472 list_for_each(p
, &map
->sdata
) {
473 sd
= list_entry(p
, struct uci_sectmap_data
, list
);
476 if (strcmp(f
->name
, sd
->section_name
) != 0)
478 ret
= (char *)sd
+ sizeof(struct uci_sectmap_data
);
485 ucimap_parse(struct uci_map
*map
, struct uci_package
*pkg
)
487 struct uci_element
*e
;
488 struct list_head
*p
, *tmp
;
491 INIT_LIST_HEAD(&map
->fixup
);
492 uci_foreach_element(&pkg
->sections
, e
) {
493 struct uci_section
*s
= uci_to_section(e
);
495 for (i
= 0; i
< map
->n_sections
; i
++) {
496 if (strcmp(s
->type
, map
->sections
[i
]->type
) != 0)
498 ucimap_parse_section(map
, map
->sections
[i
], s
);
501 list_for_each_safe(p
, tmp
, &map
->fixup
) {
502 struct uci_fixup
*f
= list_entry(p
, struct uci_fixup
, list
);
503 void *ptr
= ucimap_find_section(map
, f
);
504 struct ucimap_list
*list
;
509 switch(f
->type
& UCIMAP_TYPE
) {
511 f
->data
->section
= ptr
;
514 list
= f
->data
->list
;
515 list
->item
[list
->n_items
++].section
= ptr
;
520 list_for_each_safe(p
, tmp
, &map
->sdata
) {
521 struct uci_sectmap_data
*sd
= list_entry(p
, struct uci_sectmap_data
, list
);
527 section
= (char *) sd
+ sizeof(struct uci_sectmap_data
);
528 if (sd
->sm
->add(map
, section
) != 0)
529 ucimap_free_section(map
, sd
);