2 * UCW Library -- Reading of configuration files
4 * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5 * (c) 2003--2006 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
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"
24 #define TRY(f) do { byte *_msg = f; if (_msg) return _msg; } while (0)
26 /* Memory allocation */
28 struct mempool *cf_pool; // current pool for loading new configuration
29 static struct old_pools {
30 struct old_pools *prev;
32 } *pools; // link-list of older cf_pool's
37 return mp_alloc(cf_pool, size);
41 cf_malloc_zero(uns size)
43 return mp_alloc_zero(cf_pool, size);
49 return mp_strdup(cf_pool, s);
53 cf_printf(char *fmt, ...)
57 byte *res = mp_vprintf(cf_pool, fmt, args);
64 uns cf_need_journal; // some programs do not need journal
65 static struct journal_item {
66 struct journal_item *prev;
73 cf_journal_block(void *ptr, uns len)
77 struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
81 memcpy(ji->copy, ptr, len);
87 // swaps the contents of the memory and the journal, and reverses the list
89 struct journal_item *curr, *prev, *next;
90 for (next=NULL, curr=journal; curr; next=curr, curr=prev)
94 for (uns i=0; i<curr->len; i++)
96 byte x = curr->copy[i];
97 curr->copy[i] = curr->ptr[i];
104 static struct journal_item *
105 journal_new_section(uns new_pool)
108 cf_pool = mp_new(1<<14);
109 struct journal_item *oldj = journal;
115 journal_commit_section(uns new_pool, struct journal_item *oldj)
119 struct old_pools *p = cf_malloc(sizeof(struct old_pools));
126 struct journal_item **j = &journal;
134 journal_rollback_section(uns new_pool, struct journal_item *oldj)
136 if (!cf_need_journal)
137 die("Cannot rollback the configuration, because the journal is disabled.");
143 cf_pool = pools ? pools->pool : NULL;
149 #define SEC_FLAG_DYNAMIC 0x80000000 // contains a dynamic attribute
150 #define SEC_FLAG_NUMBER 0x7fffffff // number of entries
152 static struct cf_section sections; // root section
154 static struct cf_item *
155 find_subitem(struct cf_section *sec, byte *name)
157 struct cf_item *ci = sec->cfg;
158 for (; ci->cls; ci++)
159 if (!strcasecmp(ci->name, name))
165 inspect_section(struct cf_section *sec)
169 for (ci=sec->cfg; ci->cls; ci++)
170 if (ci->cls == CC_SECTION) {
171 inspect_section(ci->u.sec);
172 sec->flags |= ci->u.sec->flags & SEC_FLAG_DYNAMIC;
173 } else if (ci->cls == CC_LIST) {
174 inspect_section(ci->u.sec);
175 sec->flags |= SEC_FLAG_DYNAMIC;
176 } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_PARSER && ci->number < 0)
177 sec->flags |= SEC_FLAG_DYNAMIC;
178 sec->flags |= ci - sec->cfg; // record the number of entries
182 cf_declare_section(byte *name, struct cf_section *sec)
187 sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
189 struct cf_item *ci = find_subitem(§ions, name);
191 die("Cannot register section %s twice", name);
192 ci->cls = CC_SECTION;
197 inspect_section(sec);
199 if (ci - sections.cfg >= (int) sections.size)
201 sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
202 bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
208 cf_init_section(byte *name, struct cf_section *sec, void *ptr)
211 bzero(ptr, sec->size);
212 for (uns i=0; sec->cfg[i].cls; i++)
213 if (sec->cfg[i].cls == CC_SECTION)
214 cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr);
215 else if (sec->cfg[i].cls == CC_LIST)
216 clist_init(sec->cfg[i].ptr);
217 byte *msg = sec->init(ptr);
219 die("Cannot initialize section %s: %s", name, msg);
225 static uns initialized = 0;
228 for (struct cf_item *ci=sections.cfg; ci->cls; ci++)
229 cf_init_section(ci->name, ci->u.sec, NULL);
232 static struct cf_item *
233 find_item(struct cf_section *curr_sec, byte *name, byte **msg)
236 if (name[0] == '^') // absolute name instead of relative
237 name++, curr_sec = §ions;
238 if (!curr_sec) // don't even search in an unknown section
242 byte *c = strchr(name, '.');
245 struct cf_item *ci = find_subitem(curr_sec, name);
248 if (curr_sec != §ions) // ignore silently unknown top-level sections
249 *msg = cf_printf("Unknown item %s", name);
254 if (ci->cls != CC_SECTION)
256 *msg = cf_printf("Item %s is not a section", name);
259 curr_sec = ci->u.sec;
264 /* Safe loading and reloading */
266 static int load_file(byte *file);
267 static int load_string(byte *string);
270 cf_reload(byte *file)
273 struct journal_item *oldj = journal_new_section(1);
274 int err = load_file(file);
277 for (struct old_pools *p=pools; p; p=pools)
282 journal_commit_section(1, NULL);
286 journal_rollback_section(1, oldj);
295 struct journal_item *oldj = journal_new_section(1);
296 int err = load_file(file);
298 journal_commit_section(1, oldj);
300 journal_rollback_section(1, oldj);
307 struct journal_item *oldj = journal_new_section(0);
308 int err = load_string(string);
310 journal_commit_section(0, oldj);
312 journal_rollback_section(0, oldj);
316 /* Parsers for standard types */
319 uns name; // one-letter name of the unit
320 uns num, den; // fraction
323 static const struct unit units[] = {
328 { 'g', 1000000000, 1 },
331 { 'G', 1073741824, 1 },
336 static const struct unit *
337 lookup_unit(byte *value, byte *end, byte **msg)
340 if (end == value || end[1] || *end >= '0' && *end <= '9')
341 *msg = "Invalid number";
343 for (const struct unit *u=units; u->name; u++)
346 *msg = "Invalid unit";
352 static char cf_rngerr[] = "Number out of range";
354 //FIXME: parsers should handle well empty strings, unwanted suffixes etc.
356 cf_parse_int(byte *str, int *ptr)
360 msg = "Missing number";
362 const struct unit *u;
365 uns x = strtoul(str, &end, 0);
368 else if (u = lookup_unit(str, end, &msg)) {
369 u64 y = (u64)x * u->num;
371 msg = "Number is not an integer";
385 cf_parse_u64(byte *str, u64 *ptr)
389 msg = "Missing number";
391 const struct unit *u;
394 u64 x = strtoull(str, &end, 0);
397 else if (u = lookup_unit(str, end, &msg)) {
398 if (x > ~(u64)0 / u->num)
399 msg = "Number out of range";
403 msg = "Number is not an integer";
414 cf_parse_double(byte *str, double *ptr)
418 msg = "Missing number";
420 const struct unit *u;
423 double x = strtoul(str, &end, 0);
426 else if (u = lookup_unit(str, end, &msg))
427 *ptr = x * u->num / u->den;
435 cf_parse_ip(byte *p, u32 *varp)
438 return "Missing IP address";
440 if (*p == '0' && p[1] | 32 == 'X') {
442 x = strtoul(p + 2, NULL, 16);
443 if (errno == ERANGE || x > 0xffffffff)
447 for (uns i = 0; i < 4; i++) {
454 uns y = strtoul(p, &p2, 10);
456 if (errno == ERANGE || y > 255)
463 return "Invalid IP address";
467 cf_parse_string(byte *str, byte **ptr)
469 *ptr = cf_strdup(str);
473 /* Register size of and parser for each basic type */
475 typedef byte *cf_basic_parser(byte *str, void *ptr);
480 { sizeof(int), cf_parse_int },
481 { sizeof(u64), cf_parse_u64 },
482 { sizeof(double), cf_parse_double },
483 { sizeof(u32), cf_parse_ip },
484 { sizeof(byte*), cf_parse_string }
488 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type)
490 for (uns i=0; i<number; i++)
492 byte *msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * parsers[type].size);
494 return cf_printf("Cannot parse item %d: %s", i+1, msg);
501 #define OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(APPEND) T(PREPEND) \
502 T(REMOVE) T(EDIT) T(AFTER) T(BEFORE)
503 /* Closing brace finishes previous block.
504 * Basic attributes (static, dynamic, parsed) can be used with SET.
505 * Dynamic arrays can be used with SET, APPEND, PREPEND.
506 * Sections can be used with SET.
507 * Lists can be used with everything. */
514 static byte *op_names[] = {
519 #define OP_MASK 0xff // only get the operation
520 #define OP_OPEN 0x100 // here we only get an opening brace instead of parameters
521 #define OP_1ST 0x200 // in the 1st phase selectors are recorded into the mask
522 #define OP_2ND 0x400 // in the 2nd phase real data are entered
525 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
527 enum cf_type type = item->u.type;
528 cf_journal_block(ptr, sizeof(void*));
529 // boundary checks done by the caller
530 *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
531 * (uns*) (*ptr - parsers[type].size) = number;
532 return cf_parse_ary(number, pars, *ptr, type);
536 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum operation op)
538 enum cf_type type = item->u.type;
540 int old_nr = * (int*) (old_p - parsers[type].size);
541 int taken = MIN(number, item->number-old_nr);
543 // stretch the dynamic array
544 void *new_p = cf_malloc((old_nr + taken + 1) * parsers[type].size) + parsers[type].size;
545 * (uns*) (new_p - parsers[type].size) = old_nr + taken;
546 cf_journal_block(ptr, sizeof(void*));
548 if (op == OP_APPEND) {
549 memcpy(new_p, old_p, old_nr * parsers[type].size);
550 return cf_parse_ary(taken, pars, new_p + old_nr * parsers[type].size, type);
551 } else if (op == OP_PREPEND) {
552 memcpy(new_p + taken * parsers[type].size, old_p, old_nr * parsers[type].size);
553 return cf_parse_ary(taken, pars, new_p, type);
555 return cf_printf("Dynamic arrays do not support operation %s", op_names[op]);
558 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
561 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
564 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
567 byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
569 return cf_printf("Item %s: %s", ci->name, msg);
573 if (!number) // stop parsing, because many parsers would otherwise complain that number==0
580 add_to_list(void *list, struct cnode *node, enum operation op)
582 cf_journal_block(list, sizeof(struct clist)); //FIXME: we should journal the nodes of the list instead
587 clist_add_tail(list, node);
590 clist_add_head(list, node);
595 case OP_EDIT: // edition has been done in-place
597 case OP_AFTER: // here the pointer list is actually a pointer to another node
598 clist_insert_after(node, list);
601 clist_insert_before(node, list);
609 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum operation op)
612 return "Missing value";
613 ASSERT(op < OP_REMOVE);
614 struct cf_section *sec = item->u.sec;
618 void *node = cf_malloc(sec->size);
619 cf_init_section(item->name, sec, node);
620 add_to_list(ptr, node, op);
622 /* If the node contains any dynamic attribute at the end, we suppress
623 * auto-repetition here and pass the flag inside instead. */
624 TRY( interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC) );
628 if (sec->flags & SEC_FLAG_DYNAMIC)
635 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
642 return "Missing value";
643 taken = MIN(number, item->number);
645 cf_journal_block(ptr, taken * parsers[item->u.type].size);
646 return cf_parse_ary(taken, pars, ptr, item->u.type);
649 return "Dynamic array cannot be used here";
650 taken = MIN(number, item->number);
652 return interpret_set_dynamic(item, taken, pars, ptr);
654 if (item->number < 0 && !allow_dynamic)
655 return "Parsers with variable number of parameters cannot be used here";
656 if (item->number > 0 && number < item->number)
657 return "Not enough parameters available for the parser";
658 taken = MIN(number, ABS(item->number));
660 for (int i=0; i<taken; i++)
661 pars[i] = cf_strdup(pars[i]);
662 return item->u.par(taken, pars, ptr);
664 return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
667 return "Lists cannot be used here";
668 return interpret_add_list(item, number, pars, ptr, processed, OP_SET);
675 interpret_clear(struct cf_item *item, void *ptr)
677 if (item->cls == CC_LIST) {
678 cf_journal_block(ptr, sizeof(struct clist));
680 } else if (item->cls == CC_DYNAMIC) {
681 cf_journal_block(ptr, sizeof(void *));
682 * (void**) ptr = NULL;
684 return "The item is not a list or a dynamic array";
689 cmp_items(void *i1, void *i2, struct cf_item *item)
691 ASSERT(item->cls == CC_STATIC);
692 i1 += (addr_int_t) item->ptr;
693 i2 += (addr_int_t) item->ptr;
694 if (item->u.type == CT_STRING)
695 return strcmp(* (byte**) i1, * (byte**) i2);
696 else // all numeric types
697 return memcmp(i1, i2, parsers[item->u.type].size);
701 find_list_node(struct clist *list, void *query, struct cf_section *sec, u32 mask)
707 for (uns i=0; i<32; i++)
709 if (cmp_items(n, query, sec->cfg+i))
721 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
723 uns nr = sec->flags & SEC_FLAG_NUMBER;
724 if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
726 uns i = item - sec->cfg;
728 return "Cannot select list nodes by this attribute";
729 if (sec->cfg[i].cls != CC_STATIC)
730 return "Selection can only be done based on basic attributes";
736 #define MAX_STACK_SIZE 100
737 static struct item_stack {
738 struct cf_section *sec; // nested section
739 void *base_ptr; // because original pointers are often relative
740 enum operation op; // it is performed when a closing brace is encountered
741 void *list; // list the operations should be done on
742 u32 mask; // bit array of selectors searching in a list
743 struct cf_item *item; // cf_item of the list
744 } stack[MAX_STACK_SIZE];
748 opening_brace(struct cf_item *item, void *ptr, enum operation op)
750 if (level >= MAX_STACK_SIZE-1)
751 return "Too many nested sections";
752 stack[++level] = (struct item_stack) {
760 if (!item) // unknown is ignored; we just need to trace recursion
762 stack[level].sec = item->u.sec;
763 if (item->cls == CC_SECTION)
765 stack[level].base_ptr = ptr;
766 stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
768 else if (item->cls == CC_LIST)
770 stack[level].base_ptr = cf_malloc(item->u.sec->size);
771 cf_init_section(item->name, item->u.sec, stack[level].base_ptr);
772 stack[level].list = ptr;
773 stack[level].item = item;
774 stack[level].op |= op < OP_REMOVE ? OP_2ND : OP_1ST;
777 return "Opening brace can only be used on sections and lists";
782 closing_brace(struct item_stack *st, int number, byte **pars)
784 if (st->op == OP_CLOSE) // top-level
785 return "Unmatched } parenthese";
786 if (!st->sec) { // dummy run on unknown section
790 enum operation op = st->op & OP_MASK;
793 st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
795 return "Cannot find a node matching the query";
799 st->base_ptr = st->list;
800 else if (op == OP_AFTER || op == OP_BEFORE)
801 cf_init_section(st->item->name, st->sec, st->base_ptr);
804 if (st->op & OP_OPEN) { // stay at the same recursion level
805 st->op = (st->op | OP_2ND) & ~OP_1ST;
808 int taken; // parse parameters on 1 line immediately
809 TRY( interpret_section(st->sec, number, pars, &taken, st->base_ptr, 1) );
812 // and fall-thru to the 2nd phase
815 add_to_list(st->list, st->base_ptr, op);
818 return "No parameters expected after the }";
819 else if (st->op & OP_OPEN)
820 return "No { is expected";
826 interpret_line(byte *name, enum operation op, int number, byte **pars)
830 return closing_brace(stack+level, number, pars);
831 struct cf_item *item = find_item(stack[level].sec, name, &msg);
834 if (stack[level].op & OP_1ST)
835 TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
836 void *ptr = stack[level].base_ptr + (addr_int_t) item->ptr;
837 if (op & OP_OPEN) // the operation will be performed after the closing brace
838 return opening_brace(item, ptr, op);
839 if (!item) // ignored item in an unknown section
843 int taken; // process as many parameters as possible
845 taken = 0, msg = interpret_clear(item, ptr);
846 else if (op == OP_SET)
847 msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
848 else if (item->cls == CC_DYNAMIC)
849 msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
850 else if (item->cls == CC_LIST)
851 msg = interpret_add_list(item, number, pars, &taken, ptr, op);
853 return cf_printf("Operation %s not supported on attribute class %d", op_names[op], item->cls);
857 return cf_printf("Too many parameters: %d>%d", number, taken);
867 stack[0] = (struct item_stack) {
881 log(L_ERROR, "Unterminated block");
887 /* Text file parser */
889 static struct fastbuf *parse_fb;
892 #define MAX_LINE 4096
893 static byte line_buf[MAX_LINE];
894 static byte *line = line_buf;
896 #include "lib/bbuf.h"
897 static bb_t copy_buf;
900 #define GBUF_TYPE uns
901 #define GBUF_PREFIX(x) split_##x
902 #include "lib/gbuf.h"
903 static split_t word_buf;
905 static uns ends_by_brace; // the line is ended by "{"
910 if (!bgets(parse_fb, line_buf, MAX_LINE))
914 while (Cblank(*line))
920 append(byte *start, byte *end)
922 uns len = end - start;
923 bb_grow(©_buf, copied + len + 1);
924 memcpy(copy_buf.ptr + copied, start, len);
926 copy_buf.ptr[copied-1] = 0;
929 #define CONTROL_CHAR(x) (x == '{' || x == '}' || x == ';')
930 // these characters separate words like blanks
933 get_word(uns stop_at_equal)
935 // promised that *line is non-null and non-blank
940 while (*line && *line != '\'')
945 copy_buf.ptr[copied-1] = '\n';
947 return "Unterminated apostrophe word at the end";
950 } else if (*line == '"') {
956 if (*line == '"' && !escape)
958 else if (*line == '\\')
968 copy_buf.ptr[copied-1] = '\n';
969 else // merge two lines
972 return "Unterminated quoted word at the end";
977 while (*line && !Cblank(*line) && !CONTROL_CHAR(*line)
978 && (*line != '=' || !stop_at_equal))
980 if (*line == '=') { // nice for setting from a command-line
982 return "Assignment without a variable";
985 if (CONTROL_CHAR(*line)) // already the first char is control
989 while (Cblank(*line))
1000 while (!*line || *line == '#')
1004 while (*line == ';' // empty trash at the beginning
1005 || (*line == '\\' && !line[1])) {
1009 if (*line == '{') // only one opening brace
1010 return "Unexpected opening brace";
1012 /* We have got a non-null, non-blank, non-;, non-merge, and non-{ character. */
1015 split_grow(&word_buf, words+1);
1016 word_buf.ptr[words++] = copied;
1017 TRY( get_word(!words) );
1020 else if (*line == '}' || *line == ';') // end of line now and preserve the char
1022 else if (*line == '{') { // discard the char and end the line
1027 } else if (*line == '\\' && !line[1]) { // merge two lines
1029 return "Last line ends by a backslash";
1030 if (!*line || *line == '#') {
1031 log(L_WARN, "The line following the backslash is empty");
1033 } else if (*line == '{')
1040 /* Parsing multiple files */
1043 parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth)
1057 byte *name = copy_buf.ptr + word_buf.ptr[0];
1058 byte *pars[words-1];
1059 for (uns i=1; i<words; i++)
1060 pars[i-1] = copy_buf.ptr + word_buf.ptr[i];
1061 if (!strcasecmp(name, "#include"))
1064 msg = "Expecting one filename";
1068 msg = "Too many nested files";
1071 parse_fb = bopen(pars[0], O_RDONLY, 1<<14);
1073 msg = parse_fastbuf(pars[0], parse_fb, depth+1);
1081 byte *c = strchr(name, ':');
1083 op = strcmp(name, "}") ? OP_SET : OP_CLOSE;
1086 switch (Clocase(*c)) {
1087 case 's': op = OP_SET; break;
1088 case 'c': op = OP_CLEAR; break;
1089 case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
1090 case 'p': op = OP_PREPEND; break;
1091 case 'r': op = OP_REMOVE; break;
1092 case 'e': op = OP_EDIT; break;
1093 case 'b': op = OP_BEFORE; break;
1094 default: op = OP_SET; break;
1096 if (strcasecmp(c, op_names[op])) {
1097 msg = cf_printf("Unknown operation %s", c);
1103 msg = interpret_line(name, op, words-1, pars);
1108 log(L_ERROR, "File %s, line %d: %s", name_fb, line_num, msg);
1109 return "included from here";
1112 #ifndef DEFAULT_CONFIG
1113 #define DEFAULT_CONFIG NULL
1115 byte *cf_def_file = DEFAULT_CONFIG;
1118 load_file(byte *file)
1122 struct fastbuf *fb = bopen(file, O_RDONLY, 1<<14);
1123 byte *msg = parse_fastbuf(file, fb, 0);
1125 return !!msg || done_stack();
1129 load_string(byte *string)
1132 int err = load_file(cf_def_file);
1138 fbbuf_init_read(&fb, string, strlen(string), 0);
1139 byte *msg = parse_fastbuf("memory string", &fb, 0);
1140 return !!msg || done_stack();