fix segfault in extended section lookup
[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         if (e)
362                 ptr->section = e->name;
363         return e;
364 }
365
366 int
367 uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended)
368 {
369         struct uci_element *e;
370
371         UCI_HANDLE_ERR(ctx);
372         UCI_ASSERT(ctx, ptr != NULL);
373
374         if (str)
375                 UCI_INTERNAL(uci_parse_ptr, ctx, ptr, str);
376
377         ptr->flags |= UCI_LOOKUP_DONE;
378
379         /* look up the package first */
380         e = uci_lookup_list(&ctx->root, ptr->package);
381         if (!e) {
382                 UCI_INTERNAL(uci_load, ctx, ptr->package, &ptr->p);
383                 if (!ptr->p)
384                         goto notfound;
385                 ptr->last = &ptr->p->e;
386         } else {
387                 ptr->p = uci_to_package(e);
388                 ptr->last = e;
389         }
390
391         if (!ptr->section)
392                 goto complete;
393
394         /* if the section name validates as a regular name, pass through
395          * to the regular uci_lookup function call */
396         if (ptr->flags & UCI_LOOKUP_EXTENDED)
397                 e = uci_lookup_ext_section(ctx, ptr);
398         else
399                 e = uci_lookup_list(&ptr->p->sections, ptr->section);
400
401         if (!e)
402                 goto abort;
403
404         ptr->last = e;
405         ptr->s = uci_to_section(e);
406
407         if (ptr->option) {
408                 e = uci_lookup_list(&ptr->s->options, ptr->option);
409                 if (!e)
410                         goto abort;
411
412                 ptr->o = uci_to_option(e);
413                 ptr->last = e;
414         }
415
416 complete:
417         ptr->flags |= UCI_LOOKUP_COMPLETE;
418 abort:
419         return 0;
420
421 notfound:
422         UCI_THROW(ctx, UCI_ERR_NOTFOUND);
423         return 0;
424 }
425
426 int
427 uci_fill_ptr(struct uci_context *ctx, struct uci_ptr *ptr, struct uci_element *e, bool complete)
428 {
429         UCI_HANDLE_ERR(ctx);
430         UCI_ASSERT(ctx, ptr != NULL);
431         UCI_ASSERT(ctx, e != NULL);
432
433         memset(ptr, 0, sizeof(struct uci_ptr));
434         switch(e->type) {
435         case UCI_TYPE_OPTION:
436                 ptr->o = uci_to_option(e);
437                 goto fill_option;
438         case UCI_TYPE_SECTION:
439                 ptr->s = uci_to_section(e);
440                 goto fill_section;
441         case UCI_TYPE_PACKAGE:
442                 ptr->p = uci_to_package(e);
443                 goto fill_package;
444         default:
445                 UCI_THROW(ctx, UCI_ERR_INVAL);
446         }
447
448 fill_option:
449         ptr->option = ptr->o->e.name;
450         ptr->s = ptr->o->section;
451 fill_section:
452         ptr->section = ptr->s->e.name;
453         ptr->p = ptr->s->package;
454 fill_package:
455         ptr->package = ptr->p->e.name;
456
457         ptr->flags |= UCI_LOOKUP_DONE;
458         if (complete)
459                 ptr->flags |= UCI_LOOKUP_COMPLETE;
460
461         return 0;
462 }
463
464 static struct uci_element *
465 expand_ptr(struct uci_context *ctx, struct uci_ptr *ptr, bool complete)
466 {
467         UCI_ASSERT(ctx, ptr != NULL);
468
469         if (!(ptr->flags & UCI_LOOKUP_DONE))
470                 uci_lookup_ptr(ctx, ptr, NULL, 1);
471         if (complete && !(ptr->flags & UCI_LOOKUP_COMPLETE))
472                 UCI_THROW(ctx, UCI_ERR_NOTFOUND);
473         UCI_ASSERT(ctx, ptr->p != NULL);
474
475         /* fill in missing string info */
476         if (ptr->p && !ptr->package)
477                 ptr->package = ptr->p->e.name;
478         if (ptr->s && !ptr->section)
479                 ptr->section = ptr->s->e.name;
480         if (ptr->o && !ptr->option)
481                 ptr->option = ptr->o->e.name;
482
483         if (ptr->o)
484                 return &ptr->o->e;
485         if (ptr->s)
486                 return &ptr->s->e;
487         if (ptr->p)
488                 return &ptr->p->e;
489         else
490                 return NULL;
491 }
492
493 static void uci_add_element_list(struct uci_context *ctx, struct uci_ptr *ptr, bool internal)
494 {
495         struct uci_element *e;
496         struct uci_package *p;
497
498         p = ptr->p;
499         if (!internal && p->has_history)
500                 uci_add_history(ctx, &p->history, UCI_CMD_LIST_ADD, ptr->section, ptr->option, ptr->value);
501
502         e = uci_alloc_generic(ctx, UCI_TYPE_ITEM, ptr->value, sizeof(struct uci_option));
503         uci_list_add(&ptr->o->v.list, &e->list);
504 }
505
506 int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr)
507 {
508         /* NB: UCI_INTERNAL use means without history tracking */
509         bool internal = ctx->internal;
510         struct uci_element *e;
511         struct uci_package *p;
512         char *n;
513
514         UCI_HANDLE_ERR(ctx);
515
516         e = expand_ptr(ctx, ptr, true);
517         p = ptr->p;
518
519         UCI_ASSERT(ctx, ptr->s);
520         UCI_ASSERT(ctx, ptr->value);
521
522         if (!internal && p->has_history)
523                 uci_add_history(ctx, &p->history, UCI_CMD_RENAME, ptr->section, ptr->option, ptr->value);
524
525         n = uci_strdup(ctx, ptr->value);
526         if (e->name)
527                 free(e->name);
528         e->name = n;
529
530         return 0;
531 }
532
533 int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res)
534 {
535         bool internal = ctx->internal;
536         struct uci_section *s;
537
538         UCI_HANDLE_ERR(ctx);
539         UCI_ASSERT(ctx, p != NULL);
540         s = uci_alloc_section(p, type, NULL);
541         uci_fixup_section(ctx, s);
542         *res = s;
543         if (!internal && p->has_history)
544                 uci_add_history(ctx, &p->history, UCI_CMD_ADD, s->e.name, NULL, type);
545
546         return 0;
547 }
548
549 int uci_delete(struct uci_context *ctx, struct uci_ptr *ptr)
550 {
551         /* NB: pass on internal flag to uci_del_element */
552         bool internal = ctx->internal;
553         struct uci_package *p;
554         struct uci_element *e;
555
556         UCI_HANDLE_ERR(ctx);
557
558         e = expand_ptr(ctx, ptr, true);
559         p = ptr->p;
560
561         UCI_ASSERT(ctx, ptr->s);
562
563         if (!internal && p->has_history)
564                 uci_add_history(ctx, &p->history, UCI_CMD_REMOVE, ptr->section, ptr->option, NULL);
565
566         uci_free_any(&e);
567         return 0;
568 }
569
570 int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr)
571 {
572         /* NB: UCI_INTERNAL use means without history tracking */
573         bool internal = ctx->internal;
574         struct uci_option *prev = NULL;
575         const char *value2 = NULL;
576
577         UCI_HANDLE_ERR(ctx);
578
579         expand_ptr(ctx, ptr, false);
580         UCI_ASSERT(ctx, ptr->s);
581         UCI_ASSERT(ctx, ptr->value);
582
583         if (ptr->o) {
584                 switch (ptr->o->type) {
585                 case UCI_TYPE_STRING:
586                         /* we already have a string value, convert that to a list */
587                         prev = ptr->o;
588                         value2 = ptr->value;
589                         ptr->value = ptr->o->v.string;
590                         break;
591                 case UCI_TYPE_LIST:
592                         uci_add_element_list(ctx, ptr, internal);
593                         return 0;
594                 default:
595                         UCI_THROW(ctx, UCI_ERR_INVAL);
596                         break;
597                 }
598         }
599
600         ptr->o = uci_alloc_list(ptr->s, ptr->option);
601         if (prev) {
602                 uci_add_element_list(ctx, ptr, true);
603                 uci_free_option(prev);
604                 ptr->value = value2;
605         }
606         uci_add_element_list(ctx, ptr, internal);
607
608         return 0;
609 }
610
611 int uci_set(struct uci_context *ctx, struct uci_ptr *ptr)
612 {
613         /* NB: UCI_INTERNAL use means without history tracking */
614         bool internal = ctx->internal;
615
616         UCI_HANDLE_ERR(ctx);
617         expand_ptr(ctx, ptr, false);
618         UCI_ASSERT(ctx, ptr->value);
619         UCI_ASSERT(ctx, ptr->s || (!ptr->option && ptr->section));
620         if (!ptr->option) {
621                 UCI_ASSERT(ctx, uci_validate_str(ptr->value, false));
622         }
623
624         if (!ptr->o && ptr->s && ptr->option) {
625                 struct uci_element *e;
626                 e = uci_lookup_list(&ptr->s->options, ptr->option);
627                 if (e)
628                         ptr->o = uci_to_option(e);
629         }
630         if (!ptr->o && ptr->option) { /* new option */
631                 ptr->o = uci_alloc_option(ptr->s, ptr->option, ptr->value);
632                 ptr->last = &ptr->o->e;
633         } else if (!ptr->s && ptr->section) { /* new section */
634                 ptr->s = uci_alloc_section(ptr->p, ptr->value, ptr->section);
635                 ptr->last = &ptr->s->e;
636         } else if (ptr->o && ptr->option) { /* update option */
637                 if ((ptr->o->type == UCI_TYPE_STRING) &&
638                         !strcmp(ptr->o->v.string, ptr->value))
639                         return 0;
640                 uci_free_option(ptr->o);
641                 ptr->o = uci_alloc_option(ptr->s, ptr->option, ptr->value);
642                 ptr->last = &ptr->o->e;
643         } else if (ptr->s && ptr->section) { /* update section */
644                 char *s = uci_strdup(ctx, ptr->value);
645
646                 if (ptr->s->type == uci_dataptr(ptr->s)) {
647                         ptr->last = NULL;
648                         ptr->last = uci_realloc(ctx, ptr->s, sizeof(struct uci_section));
649                         ptr->s = uci_to_section(ptr->last);
650                         uci_list_fixup(&ptr->s->e.list);
651                 } else {
652                         free(ptr->s->type);
653                 }
654                 ptr->s->type = s;
655         } else {
656                 UCI_THROW(ctx, UCI_ERR_INVAL);
657         }
658
659         if (!internal && ptr->p->has_history)
660                 uci_add_history(ctx, &ptr->p->history, UCI_CMD_CHANGE, ptr->section, ptr->option, ptr->value);
661
662         return 0;
663 }
664
665 int uci_unload(struct uci_context *ctx, struct uci_package *p)
666 {
667         UCI_HANDLE_ERR(ctx);
668         UCI_ASSERT(ctx, p != NULL);
669
670         uci_free_package(&p);
671         return 0;
672 }
673