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