]> mj.ucw.cz Git - libucw.git/blob - lib/conf2.c
conf2: fix commit hooks
[libucw.git] / lib / conf2.c
1 /*
2  *      UCW Library -- Reading of configuration files
3  *
4  *      (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5  *      (c) 2003--2006 Martin Mares <mj@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include "lib/lib.h"
12 #include "lib/conf2.h"
13 #include "lib/mempool.h"
14 #include "lib/clists.h"
15 #include "lib/fastbuf.h"
16 #include "lib/chartype.h"
17 #include "lib/lfs.h"
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <fcntl.h>
24 #include <getopt.h>
25
26 #define TRY(f)  do { byte *_msg = f; if (_msg) return _msg; } while (0)
27
28 /* Memory allocation */
29
30 struct mempool *cf_pool;        // current pool for loading new configuration
31 static struct old_pools {
32   struct old_pools *prev;
33   struct mempool *pool;
34 } *pools;                       // link-list of older cf_pool's
35
36 void *
37 cf_malloc(uns size)
38 {
39   return mp_alloc(cf_pool, size);
40 }
41
42 void *
43 cf_malloc_zero(uns size)
44 {
45   return mp_alloc_zero(cf_pool, size);
46 }
47
48 byte *
49 cf_strdup(byte *s)
50 {
51   return mp_strdup(cf_pool, s);
52 }
53
54 byte *
55 cf_printf(char *fmt, ...)
56 {
57   va_list args;
58   va_start(args, fmt);
59   byte *res = mp_vprintf(cf_pool, fmt, args);
60   va_end(args);
61   return res;
62 }
63
64 /* Undo journal */
65
66 uns cf_need_journal = 1;        // some programs do not need journal
67 static struct journal_item {
68   struct journal_item *prev;
69   byte *ptr;
70   uns len;
71   byte copy[0];
72 } *journal;
73
74 void
75 cf_journal_block(void *ptr, uns len)
76 {
77   if (!cf_need_journal)
78     return;
79   struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
80   ji->prev = journal;
81   ji->ptr = ptr;
82   ji->len = len;
83   memcpy(ji->copy, ptr, len);
84   journal = ji;
85 }
86
87 static void
88 journal_swap(void)
89   // swaps the contents of the memory and the journal, and reverses the list
90 {
91   struct journal_item *curr, *prev, *next;
92   for (next=NULL, curr=journal; curr; next=curr, curr=prev)
93   {
94     prev = curr->prev;
95     curr->prev = next;
96     for (uns i=0; i<curr->len; i++)
97     {
98       byte x = curr->copy[i];
99       curr->copy[i] = curr->ptr[i];
100       curr->ptr[i] = x;
101     }
102   }
103   journal = next;
104 }
105
106 static struct journal_item *
107 journal_new_section(uns new_pool)
108 {
109   if (new_pool)
110     cf_pool = mp_new(1<<10);
111   struct journal_item *oldj = journal;
112   journal = NULL;
113   return oldj;
114 }
115
116 static void
117 journal_commit_section(uns new_pool, struct journal_item *oldj)
118 {
119   if (new_pool)
120   {
121     struct old_pools *p = cf_malloc(sizeof(struct old_pools));
122     p->prev = pools;
123     p->pool = cf_pool;
124     pools = p;
125   }
126   if (oldj)
127   {
128     struct journal_item **j = &journal;
129     while (*j)
130       j = &(*j)->prev;
131     *j = oldj;
132   }
133 }
134
135 static void
136 journal_rollback_section(uns new_pool, struct journal_item *oldj)
137 {
138   if (!cf_need_journal)
139     die("Cannot rollback the configuration, because the journal is disabled.");
140   journal_swap();
141   journal = oldj;
142   if (new_pool)
143   {
144     mp_delete(cf_pool);
145     cf_pool = pools ? pools->pool : NULL;
146   }
147 }
148
149 /* Initialization */
150
151 #define SEC_FLAG_DYNAMIC        0x80000000      // contains a dynamic attribute
152 #define SEC_FLAG_UNKNOWN        0x40000000      // ignore unknown entriies
153 #define SEC_FLAG_NUMBER         0x0fffffff      // number of entries
154
155 static struct cf_section sections;      // root section
156
157 static struct cf_item *
158 find_subitem(struct cf_section *sec, byte *name)
159 {
160   struct cf_item *ci = sec->cfg;
161   for (; ci->cls; ci++)
162     if (!strcasecmp(ci->name, name))
163       return ci;
164   return ci;
165 }
166
167 static void
168 inspect_section(struct cf_section *sec)
169 {
170   sec->flags = 0;
171   struct cf_item *ci;
172   for (ci=sec->cfg; ci->cls; ci++)
173     if (ci->cls == CC_SECTION) {
174       inspect_section(ci->u.sec);
175       sec->flags |= ci->u.sec->flags & SEC_FLAG_DYNAMIC;
176     } else if (ci->cls == CC_LIST) {
177       inspect_section(ci->u.sec);
178       sec->flags |= SEC_FLAG_DYNAMIC;
179     } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_PARSER && ci->number < 0)
180       sec->flags |= SEC_FLAG_DYNAMIC;
181   sec->flags |= ci - sec->cfg;          // record the number of entries
182 }
183
184 void
185 cf_declare_section(byte *name, struct cf_section *sec, uns allow_unknown)
186 {
187   if (!sections.cfg)
188   {
189     sections.size = 50;
190     sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
191   }
192   struct cf_item *ci = find_subitem(&sections, name);
193   if (ci->cls)
194     die("Cannot register section %s twice", name);
195   ci->cls = CC_SECTION;
196   ci->name = name;
197   ci->number = 1;
198   ci->ptr = NULL;
199   ci->u.sec = sec;
200   inspect_section(sec);
201   if (allow_unknown)
202     sec->flags |= SEC_FLAG_UNKNOWN;
203   ci++;
204   if (ci - sections.cfg >= (int) sections.size)
205   {
206     sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
207     bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
208     sections.size *= 2;
209   }
210 }
211
212 void
213 cf_init_section(byte *name, struct cf_section *sec, void *ptr, uns do_bzero)
214 {
215   if (do_bzero) {
216     ASSERT(sec->size);
217     bzero(ptr, sec->size);
218   }
219   for (uns i=0; sec->cfg[i].cls; i++)
220     if (sec->cfg[i].cls == CC_SECTION)
221       cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr, 0);
222     else if (sec->cfg[i].cls == CC_LIST)
223       clist_init(sec->cfg[i].ptr);
224   if (sec->init) {
225     byte *msg = sec->init(ptr);
226     if (msg)
227       die("Cannot initialize section %s: %s", name, msg);
228   }
229 }
230
231 static void
232 global_init(void)
233 {
234   static uns initialized = 0;
235   if (initialized++)
236     return;
237   sections.flags |= SEC_FLAG_UNKNOWN;
238   sections.size = 0;                    // size of allocated array used to be stored here
239   cf_init_section("top-level", &sections, NULL, 0);
240 }
241
242 static int
243 commit_section(byte *name, struct cf_section *sec, void *ptr)
244 {
245   struct cf_item *ci;
246   for (ci=sec->cfg; ci->cls; ci++)
247     if (ci->cls == CC_SECTION) {
248       if (commit_section(ci->name, ci->u.sec, ptr + (addr_int_t) ci->ptr)) {
249         if (sec != &sections)
250           log(L_ERROR, "It was in section %s", name);
251         return 1;
252       }
253     } else if (ci->cls == CC_LIST) {
254       struct cnode *n;
255       uns idx = 0;
256       CLIST_WALK(n, * (clist*) (ptr + (addr_int_t) ci->ptr))
257         if (idx++, commit_section(ci->name, ci->u.sec, n)) {
258           log(L_ERROR, "It was in the node #%d of list %s", idx, name);
259           return 1;
260         }
261     }
262   if (sec->commit) {
263     byte *msg = sec->commit(ptr);
264     if (msg) {
265       log(L_ERROR, "Cannot commit section %s: %s", name, msg);
266       return 1;
267     }
268   }
269   return 0;
270 }
271
272 static struct cf_item *
273 find_item(struct cf_section *curr_sec, byte *name, byte **msg, void **ptr)
274 {
275   *msg = NULL;
276   if (name[0] == '^')                           // absolute name instead of relative
277     name++, curr_sec = &sections, *ptr = NULL;
278   if (!curr_sec)                                // don't even search in an unknown section
279     return NULL;
280   while (1)
281   {
282     byte *c = strchr(name, '.');
283     if (c)
284       *c++ = 0;
285     struct cf_item *ci = find_subitem(curr_sec, name);
286     if (!ci->cls)
287     {
288       if (!(curr_sec->flags & SEC_FLAG_UNKNOWN))        // ignore silently unknown top-level sections and unknown attributes in flagged sections
289         *msg = cf_printf("Unknown item %s", name);
290       return NULL;
291     }
292     *ptr += (addr_int_t) ci->ptr;
293     if (!c)
294       return ci;
295     if (ci->cls != CC_SECTION)
296     {
297       *msg = cf_printf("Item %s is not a section", name);
298       return NULL;
299     }
300     curr_sec = ci->u.sec;
301     name = c;
302   }
303 }
304
305 byte *
306 cf_find_item(byte *name, struct cf_item *item)
307 {
308   byte *msg;
309   void *ptr;
310   struct cf_item *ci = find_item(&sections, name, &msg, &ptr);
311   if (msg)
312     return msg;
313   *item = *ci;
314   item->ptr = ptr;
315   return NULL;
316 }
317
318 /* Safe loading and reloading */
319
320 static int load_file(byte *file);
321 static int load_string(byte *string);
322
323 int
324 cf_reload(byte *file)
325 {
326   journal_swap();
327   struct journal_item *oldj = journal_new_section(1);
328   int err = load_file(file);
329   if (!err)
330   {
331     for (struct old_pools *p=pools; p; p=pools)
332     {
333       pools = p->prev;
334       mp_delete(p->pool);
335     }
336     journal_commit_section(1, NULL);
337   }
338   else
339   {
340     journal_rollback_section(1, oldj);
341     journal_swap();
342   }
343   return err;
344 }
345
346 int
347 cf_load(byte *file)
348 {
349   struct journal_item *oldj = journal_new_section(1);
350   int err = load_file(file);
351   if (!err)
352     journal_commit_section(1, oldj);
353   else
354     journal_rollback_section(1, oldj);
355   return err;
356 }
357
358 int
359 cf_set(byte *string)
360 {
361   struct journal_item *oldj = journal_new_section(0);
362   int err = load_string(string);
363   if (!err)
364     journal_commit_section(0, oldj);
365   else
366     journal_rollback_section(0, oldj);
367   return err;
368 }
369
370 /* Parsers for standard types */
371
372 struct unit {
373   uns name;                     // one-letter name of the unit
374   uns num, den;                 // fraction
375 };
376
377 static const struct unit units[] = {
378   { 'd', 86400, 1 },
379   { 'h', 3600, 1 },
380   { 'k', 1000, 1 },
381   { 'm', 1000000, 1 },
382   { 'g', 1000000000, 1 },
383   { 'K', 1024, 1 },
384   { 'M', 1048576, 1 },
385   { 'G', 1073741824, 1 },
386   { '%', 1, 100 },
387   { 0, 0, 0 }
388 };
389
390 static const struct unit *
391 lookup_unit(byte *value, byte *end, byte **msg)
392 {
393   if (end && *end) {
394     if (end == value || end[1] || *end >= '0' && *end <= '9')
395       *msg = "Invalid number";
396     else {
397       for (const struct unit *u=units; u->name; u++)
398         if (u->name == *end)
399           return u;
400       *msg = "Invalid unit";
401     }
402   }
403   return NULL;
404 }
405
406 static char cf_rngerr[] = "Number out of range";
407
408 byte *
409 cf_parse_int(byte *str, int *ptr)
410 {
411   byte *msg = NULL;
412   if (!*str)
413     msg = "Missing number";
414   else {
415     const struct unit *u;
416     char *end;
417     errno = 0;
418     uns x = strtoul(str, &end, 0);
419     if (errno == ERANGE)
420       msg = cf_rngerr;
421     else if (u = lookup_unit(str, end, &msg)) {
422       u64 y = (u64)x * u->num;
423       if (y % u->den)
424         msg = "Number is not an integer";
425       else {
426         y /= u->den;
427         if (y > 0xffffffff)
428           msg = cf_rngerr;
429         *ptr = y;
430       }
431     } else
432       *ptr = x;
433   }
434   return msg;
435 }
436
437 byte *
438 cf_parse_u64(byte *str, u64 *ptr)
439 {
440   byte *msg = NULL;
441   if (!*str)
442     msg = "Missing number";
443   else {
444     const struct unit *u;
445     char *end;
446     errno = 0;
447     u64 x = strtoull(str, &end, 0);
448     if (errno == ERANGE)
449       msg = cf_rngerr;
450     else if (u = lookup_unit(str, end, &msg)) {
451       if (x > ~(u64)0 / u->num)
452         msg = "Number out of range";
453       else {
454         x *= u->num;
455         if (x % u->den)
456           msg = "Number is not an integer";
457         else
458           *ptr = x / u->den;
459       }
460     } else
461       *ptr = x;
462   }
463   return msg;
464 }
465
466 byte *
467 cf_parse_double(byte *str, double *ptr)
468 {
469   byte *msg = NULL;
470   if (!*str)
471     msg = "Missing number";
472   else {
473     const struct unit *u;
474     double x;
475     uns read_chars;
476     if (sscanf(str, "%lf%n", &x, &read_chars) != 1)
477       msg = "Invalid number";
478     else if (u = lookup_unit(str, str + read_chars, &msg))
479       *ptr = x * u->num / u->den;
480     else
481       *ptr = x;
482   }
483   return msg;
484 }
485
486 byte *
487 cf_parse_ip(byte *p, u32 *varp)
488 {
489   if (!*p)
490     return "Missing IP address";
491   uns x = 0;
492   char *p2;
493   if (*p == '0' && p[1] | 32 == 'X') {
494     errno = 0;
495     x = strtoul(p + 2, &p2, 16);
496     if (errno == ERANGE || p2 == (char*) (p+2) || x > 0xffffffff)
497       goto error;
498     p = p2;
499   }
500   else
501     for (uns i = 0; i < 4; i++) {
502       if (i) {
503         if (*p++ != '.')
504           goto error;
505       }
506       errno = 0;
507       uns y = strtoul(p, &p2, 10);
508       if (errno == ERANGE || p2 == (char*) p || y > 255)
509         goto error;
510       p = p2;
511       x = (x << 8) + y;
512     }
513   *varp = x;
514   return *p ? "Trailing characters" : NULL;
515 error:
516   return "Invalid IP address";
517 }
518
519 static byte *
520 cf_parse_string(byte *str, byte **ptr)
521 {
522   *ptr = cf_strdup(str);
523   return NULL;
524 }
525
526 /* Register size of and parser for each basic type */
527
528 typedef byte *cf_basic_parser(byte *str, void *ptr);
529 static struct {
530   uns size;
531   void *parser;
532 } parsers[] = {
533   { sizeof(int), cf_parse_int },
534   { sizeof(u64), cf_parse_u64 },
535   { sizeof(double), cf_parse_double },
536   { sizeof(u32), cf_parse_ip },
537   { sizeof(byte*), cf_parse_string }
538 };
539
540 static byte *
541 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
542 {
543   for (uns i=0; i<number; i++)
544   {
545     byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
546     if (msg)
547       return cf_printf("Cannot parse item %d: %s", i+1, msg);
548   }
549   return NULL;
550 }
551
552 /* Interpreter */
553
554 #define T(x) #x,
555 static byte *op_names[] = { CF_OPERATIONS };
556 #undef T
557
558 #define OP_MASK 0xff            // only get the operation
559 #define OP_OPEN 0x100           // here we only get an opening brace instead of parameters
560 #define OP_1ST 0x200            // in the 1st phase selectors are recorded into the mask
561 #define OP_2ND 0x400            // in the 2nd phase real data are entered
562
563 static byte *
564 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
565 {
566   enum cf_type type = item->u.type;
567   cf_journal_block(ptr, sizeof(void*));
568   // boundary checks done by the caller
569   *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
570   * (uns*) (*ptr - parsers[type].size) = number;
571   return cf_parse_ary(number, pars, *ptr, type);
572 }
573
574 static byte *
575 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum cf_operation op)
576 {
577   enum cf_type type = item->u.type;
578   void *old_p = *ptr;
579   int old_nr = * (int*) (old_p - parsers[type].size);
580   int taken = MIN(number, item->number-old_nr);
581   *processed = taken;
582   // stretch the dynamic array
583   void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size;
584   * (uns*) (new_p - parsers[type].size) = old_nr + taken;
585   cf_journal_block(ptr, sizeof(void*));
586   *ptr = new_p;
587   if (op == OP_APPEND) {
588     memcpy(new_p, old_p, old_nr * parsers[type].size);
589     return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type);
590   } else if (op == OP_PREPEND) {
591     memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size);
592     return cf_parse_ary(taken, pars, new_p, type);
593   } else
594     return cf_printf("Dynamic arrays do not support operation %s", op_names[op]);
595 }
596
597 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
598
599 static byte *
600 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
601 {
602   *processed = 0;
603   for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
604   {
605     int taken;
606     byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
607     if (msg)
608       return cf_printf("Item %s: %s", ci->name, msg);
609     *processed += taken;
610     number -= taken;
611     pars += taken;
612     if (!number)                // stop parsing, because many parsers would otherwise complain that number==0
613       break;
614   }
615   return NULL;
616 }
617
618 static void
619 add_to_list(struct cnode *where, struct cnode *new_node, enum cf_operation op)
620 {
621   switch (op)
622   {
623     case OP_EDIT:               // edition has been done in-place
624       break;
625     case OP_REMOVE:
626       cf_journal_block(&where->prev->next, sizeof(void*));
627       cf_journal_block(&where->next->prev, sizeof(void*));
628       clist_remove(where);
629       break;
630     case OP_AFTER:              // implementation dependend (prepend_head = after(list)), and where==list, see clists.h:74
631     case OP_PREPEND:
632       cf_journal_block(&where->next->prev, sizeof(void*));
633       cf_journal_block(&where->next, sizeof(void*));
634       clist_insert_after(new_node, where);
635       break;
636     case OP_BEFORE:             // implementation dependend (append_tail = before(list))
637     case OP_APPEND:
638     case OP_SET:
639       cf_journal_block(&where->prev->next, sizeof(void*));
640       cf_journal_block(&where->prev, sizeof(void*));
641       clist_insert_before(new_node, where);
642       break;
643     default:
644       ASSERT(0);
645   }
646 }
647
648 static byte *
649 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum cf_operation op)
650 {
651   if (op >= OP_REMOVE)
652     return cf_printf("You have to open a block for operation %s", op_names[op]);
653   if (!number)
654     return "Nothing to add to the list";
655   struct cf_section *sec = item->u.sec;
656   *processed = 0;
657   while (number > 0)
658   {
659     void *node = cf_malloc(sec->size);
660     cf_init_section(item->name, sec, node, 1);
661     add_to_list(ptr, node, op);
662     int taken;
663     /* If the node contains any dynamic attribute at the end, we suppress
664      * auto-repetition here and pass the flag inside instead.  */
665     TRY( interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC) );
666     *processed += taken;
667     number -= taken;
668     pars += taken;
669     if (sec->flags & SEC_FLAG_DYNAMIC)
670       break;
671   }
672   return NULL;
673 }
674
675 static byte *
676 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
677 {
678   int taken;
679   switch (item->cls)
680   {
681     case CC_STATIC:
682       if (!number)
683         return "Missing value";
684       taken = MIN(number, item->number);
685       *processed = taken;
686       cf_journal_block(ptr, taken * parsers[item->u.type].size);
687       return cf_parse_ary(taken, pars, ptr, item->u.type);
688     case CC_DYNAMIC:
689       if (!allow_dynamic)
690         return "Dynamic array cannot be used here";
691       taken = MIN(number, item->number);
692       *processed = taken;
693       return interpret_set_dynamic(item, taken, pars, ptr);
694     case CC_PARSER:
695       if (item->number < 0 && !allow_dynamic)
696         return "Parsers with variable number of parameters cannot be used here";
697       if (item->number > 0 && number < item->number)
698         return "Not enough parameters available for the parser";
699       taken = MIN(number, ABS(item->number));
700       *processed = taken;
701       for (int i=0; i<taken; i++)
702         pars[i] = cf_strdup(pars[i]);
703       return item->u.par(taken, pars, ptr);
704     case CC_SECTION:
705       return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
706     case CC_LIST:
707       if (!allow_dynamic)
708         return "Lists cannot be used here";
709       return interpret_add_list(item, number, pars, processed, ptr, OP_SET);
710     default:
711       ASSERT(0);
712   }
713 }
714
715 static byte *
716 interpret_clear(struct cf_item *item, void *ptr)
717 {
718   if (item->cls == CC_LIST) {
719     cf_journal_block(ptr, sizeof(struct clist));
720     clist_init(ptr);
721   } else if (item->cls == CC_DYNAMIC) {
722     cf_journal_block(ptr, sizeof(void *));
723     * (void**) ptr = NULL;
724   } else
725     return "The item is not a list or a dynamic array";
726   return NULL;
727 }
728
729 static int
730 cmp_items(void *i1, void *i2, struct cf_item *item)
731 {
732   ASSERT(item->cls == CC_STATIC);
733   i1 += (addr_int_t) item->ptr;
734   i2 += (addr_int_t) item->ptr;
735   if (item->u.type == CT_STRING)
736     return strcmp(* (byte**) i1, * (byte**) i2);
737   else                          // all numeric types
738     return memcmp(i1, i2, parsers[item->u.type].size);
739 }
740
741 static void *
742 find_list_node(struct clist *list, void *query, struct cf_section *sec, u32 mask)
743 {
744   struct cnode *n;
745   CLIST_WALK(n, *list)
746   {
747     uns found = 1;
748     for (uns i=0; i<32; i++)
749       if (mask & (1<<i))
750         if (cmp_items(n, query, sec->cfg+i))
751         {
752           found = 0;
753           break;
754         }
755     if (found)
756       return n;
757   }
758   return NULL;
759 }
760
761 static byte *
762 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
763 {
764   uns nr = sec->flags & SEC_FLAG_NUMBER;
765   if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
766   {
767     uns i = item - sec->cfg;
768     if (i >= 32)
769       return "Cannot select list nodes by this attribute";
770     if (sec->cfg[i].cls != CC_STATIC)
771       return "Selection can only be done based on basic attributes";
772     *mask |= 1 << i;
773   }
774   return NULL;
775 }
776
777 #define MAX_STACK_SIZE  100
778 static struct item_stack {
779   struct cf_section *sec;       // nested section
780   void *base_ptr;               // because original pointers are often relative
781   enum cf_operation op;         // it is performed when a closing brace is encountered
782   void *list;                   // list the operations should be done on
783   u32 mask;                     // bit array of selectors searching in a list
784   struct cf_item *item;         // cf_item of the list
785 } stack[MAX_STACK_SIZE];
786 static uns level;
787
788 static byte *
789 opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
790 {
791   if (level >= MAX_STACK_SIZE-1)
792     return "Too many nested sections";
793   stack[++level] = (struct item_stack) {
794     .sec = NULL,
795     .base_ptr = NULL,
796     .op = op & OP_MASK,
797     .list = NULL,
798     .mask = 0,
799     .item = NULL,
800   };
801   if (!item)                    // unknown is ignored; we just need to trace recursion
802     return NULL;
803   stack[level].sec = item->u.sec;
804   if (item->cls == CC_SECTION)
805   {
806     stack[level].base_ptr = ptr;
807     stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
808   }
809   else if (item->cls == CC_LIST)
810   {
811     stack[level].base_ptr = cf_malloc(item->u.sec->size);
812     cf_init_section(item->name, item->u.sec, stack[level].base_ptr, 1);
813     stack[level].list = ptr;
814     stack[level].item = item;
815     stack[level].op |= (op & OP_MASK) < OP_REMOVE ? OP_2ND : OP_1ST;
816   }
817   else
818     return "Opening brace can only be used on sections and lists";
819   return NULL;
820 }
821
822 static byte *
823 closing_brace(struct item_stack *st, enum cf_operation op, int number, byte **pars)
824 {
825   if (st->op == OP_CLOSE)       // top-level
826     return "Unmatched } parenthesis";
827   if (!st->sec) {               // dummy run on unknown section
828     if (!(op & OP_OPEN))
829       level--;
830     return NULL;
831   }
832   enum cf_operation pure_op = st->op & OP_MASK;
833   if (st->op & OP_1ST)
834   {
835     st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
836     if (!st->list)
837       return "Cannot find a node matching the query";
838     if (pure_op != OP_REMOVE)
839     {
840       if (pure_op == OP_EDIT)
841         st->base_ptr = st->list;
842       else if (pure_op == OP_AFTER || pure_op == OP_BEFORE)
843         cf_init_section(st->item->name, st->sec, st->base_ptr, 1);
844       else
845         ASSERT(0);
846       if (op & OP_OPEN) {       // stay at the same recursion level
847         st->op = (st->op | OP_2ND) & ~OP_1ST;
848         return NULL;
849       }
850       int taken;                // parse parameters on 1 line immediately
851       TRY( interpret_section(st->sec, number, pars, &taken, st->base_ptr, 1) );
852       number -= taken;
853       pars += taken;
854       // and fall-thru to the 2nd phase
855     }
856   }
857   add_to_list(st->list, st->base_ptr, pure_op);
858   level--;
859   if (number)
860     return "No parameters expected after the }";
861   else if (op & OP_OPEN)
862     return "No { is expected";
863   else
864     return NULL;
865 }
866
867 static byte *
868 interpret_line(byte *name, enum cf_operation op, int number, byte **pars)
869 {
870   byte *msg;
871   if ((op & OP_MASK) == OP_CLOSE)
872     return closing_brace(stack+level, op, number, pars);
873   void *ptr = stack[level].base_ptr;
874   struct cf_item *item = find_item(stack[level].sec, name, &msg, &ptr);
875   if (msg)
876     return msg;
877   if (stack[level].op & OP_1ST)
878     TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
879   if (op & OP_OPEN)             // the operation will be performed after the closing brace
880     return opening_brace(item, ptr, op);
881   if (!item)                    // ignored item in an unknown section
882     return NULL;
883   op &= OP_MASK;
884
885   int taken;                    // process as many parameters as possible
886   if (op == OP_CLEAR)
887     taken = 0, msg = interpret_clear(item, ptr);
888   else if (op == OP_SET)
889     msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
890   else if (item->cls == CC_DYNAMIC)
891     msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
892   else if (item->cls == CC_LIST)
893     msg = interpret_add_list(item, number, pars, &taken, ptr, op);
894   else
895     return cf_printf("Operation %s not supported on attribute %s", op_names[op], name);
896   if (msg)
897     return msg;
898   if (taken < number)
899     return cf_printf("Too many parameters: %d>%d", number, taken);
900
901   return NULL;
902 }
903
904 byte *
905 cf_write_item(struct cf_item *item, enum cf_operation op, int number, byte **pars)
906 {
907   byte *msg;
908   int taken;
909   switch (op) {
910     case OP_SET:
911       msg = interpret_set_item(item, number, pars, &taken, item->ptr, 1);
912       break;
913     case OP_CLEAR:
914       taken = 0;
915       msg = interpret_clear(item, item->ptr);
916       break;
917     case OP_APPEND:
918     case OP_PREPEND:
919       if (item->cls == CC_DYNAMIC)
920         msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
921       else if (item->cls == CC_LIST)
922         msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
923       else
924         return "The attribute class does not support append/prepend";
925       break;
926     default:
927       return "Unsupported operation";
928   }
929   if (msg)
930     return msg;
931   if (taken < number)
932     return "Too many parameters";
933   return NULL;
934 }
935
936 static void
937 init_stack(void)
938 {
939   global_init();
940   level = 0;
941   stack[0] = (struct item_stack) {
942     .sec = &sections,
943     .base_ptr = NULL,
944     .op = OP_CLOSE,
945     .list = NULL,
946     .mask = 0,
947     .item = NULL
948   };
949 }
950
951 static int
952 done_stack(void)
953 {
954   if (level > 0) {
955     log(L_ERROR, "Unterminated block");
956     return 1;
957   }
958   if (commit_section("top-level", &sections, NULL))
959     return 1;
960   return 0;
961 }
962
963 /* Text file parser */
964
965 static byte *name_parse_fb;
966 static struct fastbuf *parse_fb;
967 static uns line_num;
968
969 #define MAX_LINE        4096
970 static byte line_buf[MAX_LINE];
971 static byte *line = line_buf;
972
973 #include "lib/bbuf.h"
974 static bb_t copy_buf;
975 static uns copied;
976
977 #define GBUF_TYPE       uns
978 #define GBUF_PREFIX(x)  split_##x
979 #include "lib/gbuf.h"
980 static split_t word_buf;
981 static uns words;
982 static uns ends_by_brace;               // the line is ended by "{"
983
984 static int
985 get_line(void)
986 {
987   if (!bgets(parse_fb, line_buf, MAX_LINE))
988     return 0;
989   line_num++;
990   line = line_buf;
991   while (Cblank(*line))
992     line++;
993   return 1;
994 }
995
996 static void
997 append(byte *start, byte *end)
998 {
999   uns len = end - start;
1000   bb_grow(&copy_buf, copied + len + 1);
1001   memcpy(copy_buf.ptr + copied, start, len);
1002   copied += len + 1;
1003   copy_buf.ptr[copied-1] = 0;
1004 }
1005
1006 #define CONTROL_CHAR(x) (x == '{' || x == '}' || x == ';')
1007   // these characters separate words like blanks
1008
1009 static byte *
1010 get_word(uns is_command_name)
1011 {
1012   if (*line == '\'') {
1013     line++;
1014     while (1) {
1015       byte *start = line;
1016       while (*line && *line != '\'')
1017         line++;
1018       append(start, line);
1019       if (*line)
1020         break;
1021       copy_buf.ptr[copied-1] = '\n';
1022       if (!get_line())
1023         return "Unterminated apostrophe word at the end";
1024     }
1025     line++;
1026
1027   } else if (*line == '"') {
1028     line++;
1029     uns start_copy = copied;
1030     while (1) {
1031       byte *start = line;
1032       uns escape = 0;
1033       while (*line) {
1034         if (*line == '"' && !escape)
1035           break;
1036         else if (*line == '\\')
1037           escape ^= 1;
1038         else
1039           escape = 0;
1040         line++;
1041       }
1042       append(start, line);
1043       if (*line)
1044         break;
1045       if (!escape)
1046         copy_buf.ptr[copied-1] = '\n';
1047       else // merge two lines
1048         copied -= 2;
1049       if (!get_line())
1050         return "Unterminated quoted word at the end";
1051     }
1052     line++;
1053
1054     for (byte *c=copy_buf.ptr+start_copy; *c; c++)
1055       if (*c == '%') {
1056         if (c[1] != '%')
1057           return "Formating sequences are not allowed";
1058         else
1059           c++;
1060       }
1061     byte *tmp = cf_printf(copy_buf.ptr + start_copy);
1062     uns l = strlen(tmp);
1063     bb_grow(&copy_buf, start_copy + l + 1);
1064     strcpy(copy_buf.ptr + start_copy, tmp);
1065     copied = start_copy + l + 1;
1066
1067   } else {
1068     // promised that *line is non-null and non-blank
1069     byte *start = line;
1070     while (*line && !Cblank(*line) && !CONTROL_CHAR(*line)
1071         && (*line != '=' || !is_command_name))
1072       line++;
1073     if (*line == '=') {                         // nice for setting from a command-line
1074       if (line == start)
1075         return "Assignment without a variable";
1076       *line = ' ';
1077     }
1078     if (line == start)                          // already the first char is control
1079       line++;
1080     append(start, line);
1081   }
1082   while (Cblank(*line))
1083     line++;
1084   return NULL;
1085 }
1086
1087 static byte *
1088 get_token(uns is_command_name, byte **msg)
1089 {
1090   *msg = NULL;
1091   while (1) {
1092     if (!*line || *line == '#') {
1093       if (!is_command_name || !get_line())
1094         return NULL;
1095     } else if (*line == ';') {
1096       *msg = get_word(0);
1097       if (!is_command_name || *msg)
1098         return NULL;
1099     } else if (*line == '\\' && !line[1]) {
1100       if (!get_line()) {
1101         *msg = "Last line ends by a backslash";
1102         return NULL;
1103       }
1104       if (!*line || *line == '#')
1105         log(L_WARN, "The line %s:%d following a backslash is empty", name_parse_fb, line_num);
1106     } else {
1107       split_grow(&word_buf, words+1);
1108       uns start = copied;
1109       word_buf.ptr[words++] = copied;
1110       *msg = get_word(is_command_name);
1111       return *msg ? NULL : copy_buf.ptr + start;
1112     }
1113   }
1114 }
1115
1116 static byte *
1117 split_command(void)
1118 {
1119   words = copied = ends_by_brace = 0;
1120   byte *msg, *start_word;
1121   if (!(start_word = get_token(1, &msg)))
1122     return msg;
1123   if (*start_word == '{')                       // only one opening brace
1124     return "Unexpected opening brace";
1125   while (*line != '}')                          // stays for the next time
1126   {
1127     if (!(start_word = get_token(0, &msg)))
1128       return msg;
1129     if (*start_word == '{') {
1130       words--;                                  // discard the brace
1131       ends_by_brace = 1;
1132       break;
1133     }
1134   }
1135   return NULL;
1136 }
1137
1138 /* Parsing multiple files */
1139
1140 static struct fastbuf *
1141 bopen_safe(byte *name)
1142 {
1143   int fd = sh_open(name, O_RDONLY);
1144   if (fd < 0) {
1145     log(L_ERROR, "Cannot open %s", name);
1146     return NULL;
1147   }
1148   return bopen(name, O_RDONLY, 1<<14);
1149 }
1150
1151 static byte *
1152 parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth)
1153 {
1154   byte *msg;
1155   name_parse_fb = name_fb;
1156   parse_fb = fb;
1157   line_num = 0;
1158   line = line_buf;
1159   *line = 0;
1160   while (1)
1161   {
1162     msg = split_command();
1163     if (msg)
1164       goto error;
1165     if (!words)
1166       return NULL;
1167     byte *name = copy_buf.ptr + word_buf.ptr[0];
1168     byte *pars[words-1];
1169     for (uns i=1; i<words; i++)
1170       pars[i-1] = copy_buf.ptr + word_buf.ptr[i];
1171     if (!strcasecmp(name, "include"))
1172     {
1173       if (words != 2) {
1174         msg = "Expecting one filename";
1175         goto error;
1176       }
1177       if (depth > 8) {
1178         msg = "Too many nested files";
1179         goto error;
1180       }
1181       struct fastbuf *new_fb = bopen_safe(pars[0]);
1182       if (!new_fb) {
1183         msg = "Cannot open file";
1184         goto error;
1185       }
1186       uns ll = line_num;
1187       msg = parse_fastbuf(pars[0], new_fb, depth+1);
1188       bclose(new_fb);
1189       if (msg)
1190         goto error;
1191       line_num = ll;
1192       parse_fb = fb;
1193     }
1194     enum cf_operation op;
1195     byte *c = strchr(name, ':');
1196     if (!c)
1197       op = strcmp(name, "}") ? OP_SET : OP_CLOSE;
1198     else {
1199       *c++ = 0;
1200       switch (Clocase(*c)) {
1201         case 's': op = OP_SET; break;
1202         case 'c': op = OP_CLEAR; break;
1203         case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
1204         case 'p': op = OP_PREPEND; break;
1205         case 'r': op = OP_REMOVE; break;
1206         case 'e': op = OP_EDIT; break;
1207         case 'b': op = OP_BEFORE; break;
1208         default: op = OP_SET; break;
1209       }
1210       if (strcasecmp(c, op_names[op])) {
1211         msg = cf_printf("Unknown operation %s", c);
1212         goto error;
1213       }
1214     }
1215     if (ends_by_brace)
1216       op |= OP_OPEN;
1217     msg = interpret_line(name, op, words-1, pars);
1218     if (msg)
1219       goto error;
1220   }
1221 error:
1222   log(L_ERROR, "File %s, line %d: %s", name_fb, line_num, msg);
1223   return "included from here";
1224 }
1225
1226 #ifndef DEFAULT_CONFIG
1227 #define DEFAULT_CONFIG NULL
1228 #endif
1229 byte *cf_def_file = DEFAULT_CONFIG;
1230
1231 static int
1232 load_file(byte *file)
1233 {
1234   init_stack();
1235   struct fastbuf *fb = bopen_safe(file);
1236   if (!fb)
1237     return 1;
1238   byte *msg = parse_fastbuf(file, fb, 0);
1239   bclose(fb);
1240   int err = !!msg || done_stack();
1241   if (!err)
1242     cf_def_file = NULL;
1243   return err;
1244 }
1245
1246 static int
1247 load_string(byte *string)
1248 {
1249   init_stack();
1250   struct fastbuf fb;
1251   fbbuf_init_read(&fb, string, strlen(string), 0);
1252   byte *msg = parse_fastbuf("memory string", &fb, 0);
1253   return !!msg || done_stack();
1254 }
1255
1256 /* Command-line parser */
1257
1258 static void
1259 load_default(void)
1260 {
1261   if (cf_def_file)
1262     if (cf_load(cf_def_file))
1263       die("Cannot load default config %s", cf_def_file);
1264 }
1265
1266 int
1267 cf_get_opt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index)
1268 {
1269   static int other_options = 0;
1270   while (1) {
1271     int res = getopt_long (argc, argv, short_opts, long_opts, long_index);
1272     if (res == 'S' || res == 'C')
1273     {
1274       if (other_options)
1275         die("The -S and -C options must precede all other arguments");
1276       if (res == 'S') {
1277         load_default();
1278         if (cf_set(optarg))
1279           die("Cannot set %s", optarg);
1280       } else {
1281         if (cf_load(optarg))
1282           die("Cannot load %s", optarg);
1283       }
1284     } else {
1285       /* unhandled option or end of options */
1286       load_default();
1287       other_options++;
1288       return res;
1289     }
1290   }
1291 }
1292
1293 /* Debug dumping */
1294
1295 static void
1296 spaces(struct fastbuf *fb, uns nr)
1297 {
1298   for (uns i=0; i<nr; i++)
1299     bputs(fb, "  ");
1300 }
1301
1302 static void
1303 dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type)
1304 {
1305   switch (type) {
1306     case CT_INT:        bprintf(fb, "%d ", *(uns*)ptr); break;
1307     case CT_U64:        bprintf(fb, "%llu ", *(u64*)ptr); break;
1308     case CT_DOUBLE:     bprintf(fb, "%lg ", *(double*)ptr); break;
1309     case CT_IP:         bprintf(fb, "%08x ", *(uns*)ptr); break;
1310     case CT_STRING:     bprintf(fb, "'%s' ", *(byte**)ptr); break;
1311   }
1312 }
1313
1314 static void dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr);
1315
1316 static void
1317 dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr)
1318 {
1319   ptr += (addr_int_t) item->ptr;
1320   enum cf_type type = item->u.type;
1321   int i;
1322   spaces(fb, level);
1323   bprintf(fb, "%s: c%d #%d ", item->name, item->cls, item->number);
1324   if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC)
1325     bprintf(fb, "t%d ", type);
1326   if (item->cls == CC_STATIC) {
1327     for (i=0; i<item->number; i++)
1328       dump_basic(fb, ptr + i * parsers[type].size, type);
1329   } else if (item->cls == CC_DYNAMIC) {
1330     ptr = * (void**) ptr;
1331     if (ptr) {
1332       int real_nr = * (int*) (ptr - parsers[type].size);
1333       bprintf(fb, "##%d ", real_nr);
1334       for (i=0; i<real_nr; i++)
1335         dump_basic(fb, ptr + i * parsers[type].size, type);
1336     } else
1337       bprintf(fb, "NULL ");
1338   }
1339   bputc(fb, '\n');
1340   if (item->cls == CC_SECTION)
1341     dump_section(fb, item->u.sec, level+1, ptr);
1342   else if (item->cls == CC_LIST) {
1343     uns idx = 0;
1344     struct cnode *n;
1345     CLIST_WALK(n, * (clist*) ptr) {
1346       spaces(fb, level+1);
1347       bprintf(fb, "item %d\n", ++idx);
1348       dump_section(fb, item->u.sec, level+2, n);
1349     }
1350   }
1351 }
1352
1353 static void
1354 dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr)
1355 {
1356   spaces(fb, level);
1357   bprintf(fb, "S%d F%x:\n", sec->size, sec->flags);
1358   for (struct cf_item *item=sec->cfg; item->cls; item++)
1359     dump_item(fb, item, level, ptr);
1360 }
1361
1362 void
1363 cf_dump_sections(struct fastbuf *fb)
1364 {
1365   dump_section(fb, &sections, 0, NULL);
1366 }