• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uci/list.c

  1 /*
  2  * libuci - Library for the Unified Configuration Interface
  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 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 static bool uci_list_set_pos(struct uci_list *head, struct uci_list *ptr, int pos)
 16 {
 17         struct uci_list *old_head = ptr->prev;
 18         struct uci_list *new_head = head;
 19         struct uci_element *p = NULL;
 20 
 21         uci_list_del(ptr);
 22         uci_foreach_element(head, p) {
 23                 if (pos-- <= 0)
 24                         break;
 25                 new_head = &p->list;
 26         }
 27 
 28         uci_list_add(new_head->next, ptr);
 29 
 30         return (old_head != new_head);
 31 }
 32 
 33 static inline void uci_list_fixup(struct uci_list *ptr)
 34 {
 35         ptr->prev->next = ptr;
 36         ptr->next->prev = ptr;
 37 }
 38 
 39 /*
 40  * uci_alloc_generic allocates a new uci_element with payload
 41  * payload is appended to the struct to save memory and reduce fragmentation
 42  */
 43 __private struct uci_element *
 44 uci_alloc_generic(struct uci_context *ctx, int type, const char *name, int size)
 45 {
 46         struct uci_element *e;
 47         int datalen = size;
 48         void *ptr;
 49 
 50         ptr = uci_malloc(ctx, datalen);
 51         e = (struct uci_element *) ptr;
 52         e->type = type;
 53         if (name) {
 54                 UCI_TRAP_SAVE(ctx, error);
 55                 e->name = uci_strdup(ctx, name);
 56                 UCI_TRAP_RESTORE(ctx);
 57         }
 58         uci_list_init(&e->list);
 59         goto done;
 60 
 61 error:
 62         free(ptr);
 63         UCI_THROW(ctx, ctx->err);
 64 
 65 done:
 66         return e;
 67 }
 68 
 69 __private void
 70 uci_free_element(struct uci_element *e)
 71 {
 72         free(e->name);
 73         if (!uci_list_empty(&e->list))
 74                 uci_list_del(&e->list);
 75         free(e);
 76 }
 77 
 78 static struct uci_option *
 79 uci_alloc_option(struct uci_section *s, const char *name, const char *value)
 80 {
 81         struct uci_package *p = s->package;
 82         struct uci_context *ctx = p->ctx;
 83         struct uci_option *o;
 84 
 85         o = uci_alloc_element(ctx, option, name, strlen(value) + 1);
 86         o->type = UCI_TYPE_STRING;
 87         o->v.string = uci_dataptr(o);
 88         o->section = s;
 89         strcpy(o->v.string, value);
 90         uci_list_add(&s->options, &o->e.list);
 91 
 92         return o;
 93 }
 94 
 95 static inline void
 96 uci_free_option(struct uci_option *o)
 97 {
 98         struct uci_element *e, *tmp;
 99 
100         switch(o->type) {
101         case UCI_TYPE_STRING:
102                 if ((o->v.string != uci_dataptr(o)) &&
103                         (o->v.string != NULL))
104                         free(o->v.string);
105                 break;
106         case UCI_TYPE_LIST:
107                 uci_foreach_element_safe(&o->v.list, tmp, e) {
108                         uci_free_element(e);
109                 }
110                 break;
111         default:
112                 break;
113         }
114         uci_free_element(&o->e);
115 }
116 
117 static struct uci_option *
118 uci_alloc_list(struct uci_section *s, const char *name)
119 {
120         struct uci_package *p = s->package;
121         struct uci_context *ctx = p->ctx;
122         struct uci_option *o;
123 
124         o = uci_alloc_element(ctx, option, name, 0);
125         o->type = UCI_TYPE_LIST;
126         o->section = s;
127         uci_list_init(&o->v.list);
128         uci_list_add(&s->options, &o->e.list);
129 
130         return o;
131 }
132 
133 /* Based on an efficient hash function published by D. J. Bernstein */
134 static unsigned int djbhash(unsigned int hash, char *str)
135 {
136         int len = strlen(str);
137         int i;
138 
139         /* initial value */
140         if (hash == ~0U)
141                 hash = 5381;
142 
143         for(i = 0; i < len; i++) {
144                 hash = ((hash << 5) + hash) + str[i];
145         }
146         return (hash & 0x7FFFFFFF);
147 }
148 
149 /* fix up an unnamed section, e.g. after adding options to it */
150 static void uci_fixup_section(struct uci_context *ctx, struct uci_section *s)
151 {
152         unsigned int hash = ~0U;
153         struct uci_element *e;
154         char buf[16];
155 
156         if (!s || s->e.name)
157                 return;
158 
159         /*
160          * Generate a name for unnamed sections. This is used as reference
161          * when locating or updating the section from apps/scripts.
162          * To make multiple concurrent versions somewhat safe for updating,
163          * the name is generated from a hash of its type and name/value
164          * pairs of its option, and it is prefixed by a counter value.
165          * If the order of the unnamed sections changes for some reason,
166          * updates to them will be rejected.
167          */
168         hash = djbhash(hash, s->type);
169         uci_foreach_element(&s->options, e) {
170                 struct uci_option *o;
171                 hash = djbhash(hash, e->name);
172                 o = uci_to_option(e);
173                 switch(o->type) {
174                 case UCI_TYPE_STRING:
175                         hash = djbhash(hash, o->v.string);
176                         break;
177                 default:
178                         break;
179                 }
180         }
181         sprintf(buf, "cfg%02x%04x", s->package->n_section, hash % (1 << 16));
182         s->e.name = uci_strdup(ctx, buf);
183 }
184 
185 /* fix up option list HEAD pointers and pointer to section in options */
186 static void uci_section_fixup_options(struct uci_section *s, bool no_options)
187 {
188         struct uci_element *e;
189 
190         if (no_options) {
191                 /*
192                  * enforce empty list pointer state (s->next == s) when original
193                  * section had no options in the first place
194                  */
195                 uci_list_init(&s->options);
196                 return;
197         }
198 
199         /* fix pointers to HEAD at end/beginning of list */
200         uci_list_fixup(&s->options);
201 
202         /* fix back pointer to section in options */
203         uci_foreach_element(&s->options, e) {
204                 struct uci_option *o;
205 
206                 o = uci_to_option(e);
207                 o->section = s;
208         }
209 }
210 
211 static struct uci_section *
212 uci_alloc_section(struct uci_package *p, const char *type, const char *name)
213 {
214         struct uci_context *ctx = p->ctx;
215         struct uci_section *s;
216 
217         if (name && !name[0])
218                 name = NULL;
219 
220         s = uci_alloc_element(ctx, section, name, strlen(type) + 1);
221         uci_list_init(&s->options);
222         s->type = uci_dataptr(s);
223         s->package = p;
224         strcpy(s->type, type);
225         if (name == NULL)
226                 s->anonymous = true;
227         p->n_section++;
228 
229         uci_list_add(&p->sections, &s->e.list);
230 
231         return s;
232 }
233 
234 static void
235 uci_free_section(struct uci_section *s)
236 {
237         struct uci_element *o, *tmp;
238 
239         uci_foreach_element_safe(&s->options, tmp, o) {
240                 uci_free_option(uci_to_option(o));
241         }
242         if ((s->type != uci_dataptr(s)) &&
243                 (s->type != NULL))
244                 free(s->type);
245         uci_free_element(&s->e);
246 }
247 
248 __private struct uci_package *
249 uci_alloc_package(struct uci_context *ctx, const char *name)
250 {
251         struct uci_package *p;
252 
253         p = uci_alloc_element(ctx, package, name, 0);
254         p->ctx = ctx;
255         uci_list_init(&p->sections);
256         uci_list_init(&p->delta);
257         uci_list_init(&p->saved_delta);
258         return p;
259 }
260 
261 __private void
262 uci_free_package(struct uci_package **package)
263 {
264         struct uci_element *e, *tmp;
265         struct uci_package *p = *package;
266 
267         if(!p)
268                 return;
269 
270         free(p->path);
271         uci_foreach_element_safe(&p->sections, tmp, e) {
272                 uci_free_section(uci_to_section(e));
273         }
274         uci_foreach_element_safe(&p->delta, tmp, e) {
275                 uci_free_delta(uci_to_delta(e));
276         }
277         uci_foreach_element_safe(&p->saved_delta, tmp, e) {
278                 uci_free_delta(uci_to_delta(e));
279         }
280         uci_free_element(&p->e);
281         *package = NULL;
282 }
283 
284 static void
285 uci_free_any(struct uci_element **e)
286 {
287         switch((*e)->type) {
288         case UCI_TYPE_SECTION:
289                 uci_free_section(uci_to_section(*e));
290                 break;
291         case UCI_TYPE_OPTION:
292                 uci_free_option(uci_to_option(*e));
293                 break;
294         default:
295                 break;
296         }
297         *e = NULL;
298 }
299 
300 __private struct uci_element *
301 uci_lookup_list(struct uci_list *list, const char *name)
302 {
303         struct uci_element *e;
304 
305         uci_foreach_element(list, e) {
306                 if (!strcmp(e->name, name))
307                         return e;
308         }
309         return NULL;
310 }
311 
312 static struct uci_element *
313 uci_lookup_ext_section(struct uci_context *ctx, struct uci_ptr *ptr)
314 {
315         char *idxstr, *t, *section, *name;
316         struct uci_element *e = NULL;
317         struct uci_section *s;
318         int idx, c;
319 
320         section = uci_strdup(ctx, ptr->section);
321         name = idxstr = section + 1;
322 
323         if (section[0] != '@')
324                 goto error;
325 
326         /* parse the section index part */
327         idxstr = strchr(idxstr, '[');
328         if (!idxstr)
329                 goto error;
330         *idxstr = 0;
331         idxstr++;
332 
333         t = strchr(idxstr, ']');
334         if (!t)
335                 goto error;
336         if (t[1] != 0)
337                 goto error;
338         *t = 0;
339 
340         t = NULL;
341         idx = strtol(idxstr, &t, 10);
342         if (t && *t)
343                 goto error;
344 
345         if (!*name)
346                 name = NULL;
347         else if (!uci_validate_type(name))
348                 goto error;
349 
350         /* if the given index is negative, it specifies the section number from
351          * the end of the list */
352         if (idx < 0) {
353                 c = 0;
354                 uci_foreach_element(&ptr->p->sections, e) {
355                         s = uci_to_section(e);
356                         if (name && (strcmp(s->type, name) != 0))
357                                 continue;
358 
359                         c++;
360                 }
361                 idx += c;
362         }
363 
364         c = 0;
365         uci_foreach_element(&ptr->p->sections, e) {
366                 s = uci_to_section(e);
367                 if (name && (strcmp(s->type, name) != 0))
368                         continue;
369 
370                 if (idx == c)
371                         goto done;
372                 c++;
373         }
374         e = NULL;
375         goto done;
376 
377 error:
378         free(section);
379         memset(ptr, 0, sizeof(struct uci_ptr));
380         UCI_THROW(ctx, UCI_ERR_INVAL);
381 done:
382         free(section);
383         if (e)
384                 ptr->section = e->name;
385         return e;
386 }
387 
388 int
389 uci_lookup_next(struct uci_context *ctx, struct uci_element **e, struct uci_list *list, const char *name)
390 {
391         UCI_HANDLE_ERR(ctx);
392 
393         *e = uci_lookup_list(list, name);
394         if (!*e)
395                 UCI_THROW(ctx, UCI_ERR_NOTFOUND);
396 
397         return 0;
398 }
399 
400 int
401 uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended)
402 {
403         struct uci_element *e;
404 
405         UCI_HANDLE_ERR(ctx);
406         UCI_ASSERT(ctx, ptr != NULL);
407 
408         if (str)
409                 UCI_INTERNAL(uci_parse_ptr, ctx, ptr, str);
410 
411         ptr->flags |= UCI_LOOKUP_DONE;
412 
413         /* look up the package first */
414         if (ptr->p)
415                 e = &ptr->p->e;
416         else
417                 e = uci_lookup_list(&ctx->root, ptr->package);
418 
419         if (!e) {
420                 UCI_INTERNAL(uci_load, ctx, ptr->package, &ptr->p);
421                 if (!ptr->p)
422                         goto notfound;
423                 ptr->last = &ptr->p->e;
424         } else {
425                 ptr->p = uci_to_package(e);
426                 ptr->last = e;
427         }
428 
429         if (!ptr->section && !ptr->s)
430                 goto complete;
431 
432         /* if the section name validates as a regular name, pass through
433          * to the regular uci_lookup function call */
434         if (ptr->s) {
435                 e = &ptr->s->e;
436         } else if (ptr->flags & UCI_LOOKUP_EXTENDED) {
437                 if (extended)
438                         e = uci_lookup_ext_section(ctx, ptr);
439                 else
440                         UCI_THROW(ctx, UCI_ERR_INVAL);
441         } else {
442                 e = uci_lookup_list(&ptr->p->sections, ptr->section);
443         }
444 
445         if (!e)
446                 goto abort;
447 
448         ptr->last = e;
449         ptr->s = uci_to_section(e);
450 
451         if (ptr->option) {
452                 e = uci_lookup_list(&ptr->s->options, ptr->option);
453                 if (!e)
454                         goto abort;
455 
456                 ptr->o = uci_to_option(e);
457                 ptr->last = e;
458         }
459 
460 complete:
461         ptr->flags |= UCI_LOOKUP_COMPLETE;
462 abort:
463         return UCI_OK;
464 
465 notfound:
466         UCI_THROW(ctx, UCI_ERR_NOTFOUND);
467         /* not a chance here */
468         return UCI_ERR_NOTFOUND;
469 }
470 
471 __private struct uci_element *
472 uci_expand_ptr(struct uci_context *ctx, struct uci_ptr *ptr, bool complete)
473 {
474         UCI_ASSERT(ctx, ptr != NULL);
475 
476         if (!(ptr->flags & UCI_LOOKUP_DONE))
477                 UCI_INTERNAL(uci_lookup_ptr, ctx, ptr, NULL, 1);
478         if (complete && !(ptr->flags & UCI_LOOKUP_COMPLETE))
479                 UCI_THROW(ctx, UCI_ERR_NOTFOUND);
480         UCI_ASSERT(ctx, ptr->p != NULL);
481 
482         /* fill in missing string info */
483         if (ptr->p && !ptr->package)
484                 ptr->package = ptr->p->e.name;
485         if (ptr->s && !ptr->section)
486                 ptr->section = ptr->s->e.name;
487         if (ptr->o && !ptr->option)
488                 ptr->option = ptr->o->e.name;
489 
490         if (ptr->o)
491                 return &ptr->o->e;
492         if (ptr->s)
493                 return &ptr->s->e;
494         if (ptr->p)
495                 return &ptr->p->e;
496         else
497                 return NULL;
498 }
499 
500 static void uci_add_element_list(struct uci_context *ctx, struct uci_ptr *ptr, bool internal)
501 {
502         struct uci_element *e;
503         struct uci_package *p;
504 
505         p = ptr->p;
506         if (!internal && p->has_delta)
507                 uci_add_delta(ctx, &p->delta, UCI_CMD_LIST_ADD, ptr->section, ptr->option, ptr->value);
508 
509         e = uci_alloc_generic(ctx, UCI_TYPE_ITEM, ptr->value, sizeof(struct uci_option));
510         uci_list_add(&ptr->o->v.list, &e->list);
511 }
512 
513 int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr)
514 {
515         /* NB: UCI_INTERNAL use means without delta tracking */
516         bool internal = ctx && ctx->internal;
517         struct uci_element *e;
518         struct uci_package *p;
519         char *n;
520 
521         UCI_HANDLE_ERR(ctx);
522 
523         e = uci_expand_ptr(ctx, ptr, true);
524         p = ptr->p;
525 
526         UCI_ASSERT(ctx, ptr->s);
527         UCI_ASSERT(ctx, ptr->value);
528 
529         if (!internal && p->has_delta)
530                 uci_add_delta(ctx, &p->delta, UCI_CMD_RENAME, ptr->section, ptr->option, ptr->value);
531 
532         n = uci_strdup(ctx, ptr->value);
533         free(e->name);
534         e->name = n;
535 
536         if (e->type == UCI_TYPE_SECTION)
537                 uci_to_section(e)->anonymous = false;
538 
539         return 0;
540 }
541 
542 int uci_reorder_section(struct uci_context *ctx, struct uci_section *s, int pos)
543 {
544         struct uci_package *p = s->package;
545         bool internal = ctx && ctx->internal;
546         bool changed = false;
547         char order[32];
548 
549         UCI_HANDLE_ERR(ctx);
550 
551         changed = uci_list_set_pos(&s->package->sections, &s->e.list, pos);
552         if (!internal && p->has_delta && changed) {
553                 sprintf(order, "%d", pos);
554                 uci_add_delta(ctx, &p->delta, UCI_CMD_REORDER, s->e.name, NULL, order);
555         }
556 
557         return 0;
558 }
559 
560 int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res)
561 {
562         bool internal = ctx && ctx->internal;
563         struct uci_section *s;
564 
565         UCI_HANDLE_ERR(ctx);
566         UCI_ASSERT(ctx, p != NULL);
567         s = uci_alloc_section(p, type, NULL);
568         if (s && s->anonymous)
569                 uci_fixup_section(ctx, s);
570         *res = s;
571         if (!internal && p->has_delta)
572                 uci_add_delta(ctx, &p->delta, UCI_CMD_ADD, s->e.name, NULL, type);
573 
574         return 0;
575 }
576 
577 int uci_delete(struct uci_context *ctx, struct uci_ptr *ptr)
578 {
579         /* NB: pass on internal flag to uci_del_element */
580         bool internal = ctx && ctx->internal;
581         struct uci_package *p;
582         struct uci_element *e1, *e2, *tmp;
583         int index;
584 
585         UCI_HANDLE_ERR(ctx);
586 
587         e1 = uci_expand_ptr(ctx, ptr, true);
588         p = ptr->p;
589 
590         UCI_ASSERT(ctx, ptr->s);
591 
592         if (ptr->o && ptr->o->type == UCI_TYPE_LIST && ptr->value && *ptr->value) {
593                 if (!sscanf(ptr->value, "%d", &index))
594                         return 1;
595 
596                 uci_foreach_element_safe(&ptr->o->v.list, tmp, e2) {
597                         if (index == 0) {
598                                 if (!internal && p->has_delta)
599                                         uci_add_delta(ctx, &p->delta, UCI_CMD_REMOVE, ptr->section, ptr->option, ptr->value);
600                                 uci_free_option(uci_to_option(e2));
601                                 return 0;
602                         }
603                         index--;
604                 }
605 
606                 return 0;
607         }
608 
609         if (!internal && p->has_delta)
610                 uci_add_delta(ctx, &p->delta, UCI_CMD_REMOVE, ptr->section, ptr->option, NULL);
611 
612         uci_free_any(&e1);
613 
614         if (ptr->option)
615                 ptr->o = NULL;
616         else if (ptr->section)
617                 ptr->s = NULL;
618 
619         return 0;
620 }
621 
622 int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr)
623 {
624         /* NB: UCI_INTERNAL use means without delta tracking */
625         bool internal = ctx && ctx->internal;
626         struct uci_option *volatile prev = NULL;
627         const char *volatile value2 = NULL;
628 
629         UCI_HANDLE_ERR(ctx);
630 
631         uci_expand_ptr(ctx, ptr, false);
632         UCI_ASSERT(ctx, ptr->s);
633         UCI_ASSERT(ctx, ptr->value);
634 
635         if (ptr->o) {
636                 switch (ptr->o->type) {
637                 case UCI_TYPE_STRING:
638                         /* we already have a string value, convert that to a list */
639                         prev = ptr->o;
640                         value2 = ptr->value;
641                         ptr->value = ptr->o->v.string;
642                         break;
643                 case UCI_TYPE_LIST:
644                         uci_add_element_list(ctx, ptr, internal);
645                         return 0;
646                 default:
647                         UCI_THROW(ctx, UCI_ERR_INVAL);
648                         break;
649                 }
650         }
651 
652         ptr->o = uci_alloc_list(ptr->s, ptr->option);
653         if (prev) {
654                 uci_add_element_list(ctx, ptr, true);
655                 uci_free_option(prev);
656                 ptr->value = value2;
657         }
658         uci_add_element_list(ctx, ptr, internal);
659 
660         return 0;
661 }
662 
663 int uci_del_list(struct uci_context *ctx, struct uci_ptr *ptr)
664 {
665         /* NB: pass on internal flag to uci_del_element */
666         bool internal = ctx && ctx->internal;
667         struct uci_element *e, *tmp;
668         struct uci_package *p;
669 
670         UCI_HANDLE_ERR(ctx);
671 
672         uci_expand_ptr(ctx, ptr, false);
673         UCI_ASSERT(ctx, ptr->s);
674         UCI_ASSERT(ctx, ptr->value);
675 
676         if (!(ptr->o && ptr->option))
677                 return 0;
678 
679         if ((ptr->o->type != UCI_TYPE_LIST))
680                 return 0;
681 
682         p = ptr->p;
683         if (!internal && p->has_delta)
684                 uci_add_delta(ctx, &p->delta, UCI_CMD_LIST_DEL, ptr->section, ptr->option, ptr->value);
685 
686         uci_foreach_element_safe(&ptr->o->v.list, tmp, e) {
687                 if (!strcmp(ptr->value, uci_to_option(e)->e.name)) {
688                         uci_free_option(uci_to_option(e));
689                 }
690         }
691 
692         return 0;
693 }
694 
695 int uci_set(struct uci_context *ctx, struct uci_ptr *ptr)
696 {
697         /* NB: UCI_INTERNAL use means without delta tracking */
698         bool internal = ctx && ctx->internal;
699 
700         UCI_HANDLE_ERR(ctx);
701         uci_expand_ptr(ctx, ptr, false);
702         UCI_ASSERT(ctx, ptr->value);
703         UCI_ASSERT(ctx, ptr->s || (!ptr->option && ptr->section));
704         if (!ptr->option && ptr->value[0]) {
705                 UCI_ASSERT(ctx, uci_validate_type(ptr->value));
706         }
707 
708         if (!ptr->o && ptr->s && ptr->option) {
709                 struct uci_element *e;
710                 e = uci_lookup_list(&ptr->s->options, ptr->option);
711                 if (e)
712                         ptr->o = uci_to_option(e);
713         }
714         if (!ptr->value[0]) {
715                 /* if setting a nonexistant option/section to a nonexistant value,
716                  * exit without errors */
717                 if (!(ptr->flags & UCI_LOOKUP_COMPLETE))
718                         return 0;
719 
720                 return uci_delete(ctx, ptr);
721         } else if (!ptr->o && ptr->option) { /* new option */
722                 ptr->o = uci_alloc_option(ptr->s, ptr->option, ptr->value);
723                 ptr->last = &ptr->o->e;
724         } else if (!ptr->s && ptr->section) { /* new section */
725                 ptr->s = uci_alloc_section(ptr->p, ptr->value, ptr->section);
726                 ptr->last = &ptr->s->e;
727         } else if (ptr->o && ptr->option) { /* update option */
728                 struct uci_option *o;
729 
730                 if ((ptr->o->type == UCI_TYPE_STRING) &&
731                         !strcmp(ptr->o->v.string, ptr->value))
732                         return 0;
733 
734                 o = ptr->o;
735                 ptr->o = uci_alloc_option(ptr->s, ptr->option, ptr->value);
736                 uci_free_option(o);
737                 ptr->last = &ptr->o->e;
738         } else if (ptr->s && ptr->section) { /* update section */
739                 char *s = uci_strdup(ctx, ptr->value);
740 
741                 if (ptr->s->type == uci_dataptr(ptr->s)) {
742                         /* drop the in-section storage of type name */
743                         bool no_options;
744 
745                         no_options = uci_list_empty(&ptr->s->options);
746                         ptr->last = NULL;
747                         ptr->last = uci_realloc(ctx, ptr->s, sizeof(struct uci_section));
748                         ptr->s = uci_to_section(ptr->last);
749                         uci_list_fixup(&ptr->s->e.list);
750                         uci_section_fixup_options(ptr->s, no_options);
751                 } else {
752                         free(ptr->s->type);
753                 }
754                 ptr->s->type = s;
755         } else {
756                 UCI_THROW(ctx, UCI_ERR_INVAL);
757         }
758 
759         if (!internal && ptr->p->has_delta)
760                 uci_add_delta(ctx, &ptr->p->delta, UCI_CMD_CHANGE, ptr->section, ptr->option, ptr->value);
761 
762         return 0;
763 }
764 
765 int uci_unload(struct uci_context *ctx, struct uci_package *p)
766 {
767         UCI_HANDLE_ERR(ctx);
768         UCI_ASSERT(ctx, p != NULL);
769 
770         uci_free_package(&p);
771         return 0;
772 }
773 
774 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt