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.
13 #include "lib/getopt.h"
14 #include "lib/mempool.h"
15 #include "lib/clists.h"
16 #include "lib/fastbuf.h"
17 #include "lib/chartype.h"
19 #include "lib/stkstring.h"
20 #include "lib/binsearch.h"
28 #define TRY(f) do { byte *_msg = f; if (_msg) return _msg; } while (0)
30 /* Memory allocation */
32 struct mempool *cf_pool; // current pool for loading new configuration
33 static struct old_pools {
34 struct old_pools *prev;
36 } *pools; // link-list of older cf_pool's
41 return mp_alloc(cf_pool, size);
45 cf_malloc_zero(uns size)
47 return mp_alloc_zero(cf_pool, size);
53 return mp_strdup(cf_pool, s);
57 cf_printf(char *fmt, ...)
61 byte *res = mp_vprintf(cf_pool, fmt, args);
68 uns cf_need_journal = 1; // some programs do not need journal
69 static struct cf_journal_item {
70 struct cf_journal_item *prev;
77 cf_journal_block(void *ptr, uns len)
81 struct cf_journal_item *ji = cf_malloc(sizeof(struct cf_journal_item) + len);
85 memcpy(ji->copy, ptr, len);
91 // swaps the contents of the memory and the journal, and reverses the list
93 struct cf_journal_item *curr, *prev, *next;
94 for (next=NULL, curr=journal; curr; next=curr, curr=prev)
98 for (uns i=0; i<curr->len; i++)
100 byte x = curr->copy[i];
101 curr->copy[i] = curr->ptr[i];
108 struct cf_journal_item *
109 cf_journal_new_transaction(uns new_pool)
112 cf_pool = mp_new(1<<10);
113 struct cf_journal_item *oldj = journal;
119 cf_journal_commit_transaction(uns new_pool, struct cf_journal_item *oldj)
123 struct old_pools *p = cf_malloc(sizeof(struct old_pools));
130 struct cf_journal_item **j = &journal;
138 cf_journal_rollback_transaction(uns new_pool, struct cf_journal_item *oldj)
140 if (!cf_need_journal)
141 die("Cannot rollback the configuration, because the journal is disabled.");
147 cf_pool = pools ? pools->pool : NULL;
153 struct dirty_section {
154 struct cf_section *sec;
157 #define GBUF_TYPE struct dirty_section
158 #define GBUF_PREFIX(x) dirtsec_##x
159 #include "lib/gbuf.h"
160 static dirtsec_t dirty;
162 static uns everything_committed; // after the 1st load, this flag is set on
165 add_dirty(struct cf_section *sec, void *ptr)
167 dirtsec_grow(&dirty, dirties+1);
168 struct dirty_section *dest = dirty.ptr + dirties;
169 if (dirties && dest[-1].sec == sec && dest[-1].ptr == ptr)
176 #define ASORT_PREFIX(x) dirtsec_##x
177 #define ASORT_KEY_TYPE struct dirty_section
178 #define ASORT_ELT(i) dirty.ptr[i]
179 #define ASORT_LT(x,y) x.sec < y.sec || x.sec == y.sec && x.ptr < y.ptr
180 #include "lib/arraysort.h"
187 dirtsec_sort(dirties);
188 struct dirty_section *read = dirty.ptr + 1, *write = dirty.ptr + 1, *limit = dirty.ptr + dirties;
189 while (read < limit) {
190 if (read->sec != read[-1].sec || read->ptr != read[-1].ptr) {
197 dirties = write - dirty.ptr;
202 #define SEC_FLAG_DYNAMIC 0x80000000 // contains a dynamic attribute
203 #define SEC_FLAG_UNKNOWN 0x40000000 // ignore unknown entriies
204 #define SEC_FLAG_CANT_COPY 0x20000000 // contains lists or parsers
205 #define SEC_FLAG_NUMBER 0x0fffffff // number of entries
207 static struct cf_section sections; // root section
209 static struct cf_item *
210 find_subitem(struct cf_section *sec, byte *name)
212 struct cf_item *ci = sec->cfg;
213 for (; ci->cls; ci++)
214 if (!strcasecmp(ci->name, name))
220 inspect_section(struct cf_section *sec)
224 for (ci=sec->cfg; ci->cls; ci++)
225 if (ci->cls == CC_SECTION) {
226 inspect_section(ci->u.sec);
227 sec->flags |= ci->u.sec->flags & (SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY);
228 } else if (ci->cls == CC_LIST) {
229 inspect_section(ci->u.sec);
230 sec->flags |= SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY;
231 } else if (ci->cls == CC_DYNAMIC)
232 sec->flags |= SEC_FLAG_DYNAMIC;
233 else if (ci->cls == CC_PARSER) {
234 sec->flags |= SEC_FLAG_CANT_COPY;
236 sec->flags |= SEC_FLAG_DYNAMIC;
239 sec->flags &= ~SEC_FLAG_CANT_COPY;
240 sec->flags |= ci - sec->cfg; // record the number of entries
244 cf_declare_section(byte *name, struct cf_section *sec, uns allow_unknown)
249 sections.cfg = xmalloc_zero(sections.size * sizeof(struct cf_item));
251 struct cf_item *ci = find_subitem(§ions, name);
253 die("Cannot register section %s twice", name);
254 ci->cls = CC_SECTION;
259 inspect_section(sec);
261 sec->flags |= SEC_FLAG_UNKNOWN;
263 if (ci - sections.cfg >= (int) sections.size)
265 sections.cfg = xrealloc(sections.cfg, 2*sections.size * sizeof(struct cf_item));
266 bzero(sections.cfg + sections.size, sections.size * sizeof(struct cf_item));
272 cf_init_section(byte *name, struct cf_section *sec, void *ptr, uns do_bzero)
276 bzero(ptr, sec->size);
278 for (uns i=0; sec->cfg[i].cls; i++)
279 if (sec->cfg[i].cls == CC_SECTION)
280 cf_init_section(sec->cfg[i].name, sec->cfg[i].u.sec, ptr + (addr_int_t) sec->cfg[i].ptr, 0);
281 else if (sec->cfg[i].cls == CC_LIST)
282 clist_init(ptr + (addr_int_t) sec->cfg[i].ptr);
284 byte *msg = sec->init(ptr);
286 die("Cannot initialize section %s: %s", name, msg);
293 static uns initialized = 0;
296 sections.flags |= SEC_FLAG_UNKNOWN;
297 sections.size = 0; // size of allocated array used to be stored here
298 cf_init_section(NULL, §ions, NULL, 0);
302 commit_section(struct cf_section *sec, void *ptr, uns commit_all)
306 for (ci=sec->cfg; ci->cls; ci++)
307 if (ci->cls == CC_SECTION) {
308 if ((err = commit_section(ci->u.sec, ptr + (addr_int_t) ci->ptr, commit_all))) {
309 log(L_ERROR, "Cannot commit section %s: %s", ci->name, err);
310 return "commit of a subsection failed";
312 } else if (ci->cls == CC_LIST) {
314 CLIST_FOR_EACH(cnode *, n, * (clist*) (ptr + (addr_int_t) ci->ptr))
315 if (idx++, err = commit_section(ci->u.sec, n, commit_all)) {
316 log(L_ERROR, "Cannot commit node #%d of list %s: %s", idx, ci->name, err);
317 return "commit of a list failed";
321 /* We have to process the whole tree of sections even if just a few changes
322 * have been made, because there are dependencies between commit-hooks and
323 * hence we need to call them in a fixed order. */
324 #define ARY_LT_X(ary,i,x) ary[i].sec < x.sec || ary[i].sec == x.sec && ary[i].ptr < x.ptr
325 struct dirty_section comp = { sec, ptr };
326 uns pos = BIN_SEARCH_FIRST_GE_CMP(dirty.ptr, dirties, comp, ARY_LT_X);
329 || (pos < dirties && dirty.ptr[pos].sec == sec && dirty.ptr[pos].ptr == ptr)) {
330 return sec->commit(ptr);
336 static struct cf_item *
337 find_item(struct cf_section *curr_sec, byte *name, byte **msg, void **ptr)
340 if (name[0] == '^') // absolute name instead of relative
341 name++, curr_sec = §ions, *ptr = NULL;
342 if (!curr_sec) // don't even search in an unknown section
346 if (curr_sec != §ions)
347 add_dirty(curr_sec, *ptr);
348 byte *c = strchr(name, '.');
351 struct cf_item *ci = find_subitem(curr_sec, name);
354 if (!(curr_sec->flags & SEC_FLAG_UNKNOWN)) // ignore silently unknown top-level sections and unknown attributes in flagged sections
355 *msg = cf_printf("Unknown item %s", name);
358 *ptr += (addr_int_t) ci->ptr;
361 if (ci->cls != CC_SECTION)
363 *msg = cf_printf("Item %s is not a section", name);
366 curr_sec = ci->u.sec;
372 cf_find_item(byte *name, struct cf_item *item)
376 struct cf_item *ci = find_item(§ions, name, &msg, &ptr);
383 bzero(item, sizeof(struct cf_item));
387 /* Safe loading and reloading */
389 static int load_file(byte *file);
390 static int load_string(byte *string);
393 cf_reload(byte *file)
396 struct cf_journal_item *oldj = cf_journal_new_transaction(1);
397 uns ec = everything_committed;
398 everything_committed = 0;
399 int err = load_file(file);
402 for (struct old_pools *p=pools; p; p=pools)
407 cf_journal_commit_transaction(1, NULL);
411 everything_committed = ec;
412 cf_journal_rollback_transaction(1, oldj);
421 struct cf_journal_item *oldj = cf_journal_new_transaction(1);
422 int err = load_file(file);
424 cf_journal_commit_transaction(1, oldj);
426 cf_journal_rollback_transaction(1, oldj);
433 struct cf_journal_item *oldj = cf_journal_new_transaction(0);
434 int err = load_string(string);
436 cf_journal_commit_transaction(0, oldj);
438 cf_journal_rollback_transaction(0, oldj);
442 /* Parsers for standard types */
445 uns name; // one-letter name of the unit
446 uns num, den; // fraction
449 static const struct unit units[] = {
454 { 'g', 1000000000, 1 },
457 { 'G', 1073741824, 1 },
462 static const struct unit *
463 lookup_unit(byte *value, byte *end, byte **msg)
466 if (end == value || end[1] || *end >= '0' && *end <= '9')
467 *msg = "Invalid number";
469 for (const struct unit *u=units; u->name; u++)
472 *msg = "Invalid unit";
478 static char cf_rngerr[] = "Number out of range";
481 cf_parse_int(byte *str, int *ptr)
485 msg = "Missing number";
487 const struct unit *u;
490 uns x = strtoul(str, &end, 0);
493 else if (u = lookup_unit(str, end, &msg)) {
494 u64 y = (u64)x * u->num;
496 msg = "Number is not an integer";
510 cf_parse_u64(byte *str, u64 *ptr)
514 msg = "Missing number";
516 const struct unit *u;
519 u64 x = strtoull(str, &end, 0);
522 else if (u = lookup_unit(str, end, &msg)) {
523 if (x > ~(u64)0 / u->num)
524 msg = "Number out of range";
528 msg = "Number is not an integer";
539 cf_parse_double(byte *str, double *ptr)
543 msg = "Missing number";
545 const struct unit *u;
548 if (sscanf(str, "%lf%n", &x, &read_chars) != 1)
549 msg = "Invalid number";
550 else if (u = lookup_unit(str, str + read_chars, &msg))
551 *ptr = x * u->num / u->den;
559 cf_parse_ip(byte *p, u32 *varp)
562 return "Missing IP address";
565 if (*p == '0' && (p[1] | 32) == 'x' && Cxdigit(p[2])) {
567 x = strtoul(p, &p2, 16);
568 if (errno == ERANGE || x > 0xffffffff)
573 for (uns i = 0; i < 4; i++) {
581 uns y = strtoul(p, &p2, 10);
582 if (errno == ERANGE || p2 == (char*) p || y > 255)
588 return *p ? "Trailing characters" : NULL;
590 return "Invalid IP address";
594 cf_parse_string(byte *str, byte **ptr)
596 *ptr = cf_strdup(str);
601 cf_parse_lookup(byte *str, int *ptr, byte **t)
605 while (*n && strcasecmp(*n, str)) {
606 total_len += strlen(*n) + 2;
613 byte *err = cf_malloc(total_len + strlen(str) + 60), *c = err;
614 c += sprintf(err, "Invalid value %s, possible values are: ", str);
616 c+= sprintf(c, "%s, ", *n);
623 /* Register size of and parser for each basic type */
625 typedef byte *cf_basic_parser(byte *str, void *ptr);
630 { sizeof(int), cf_parse_int },
631 { sizeof(u64), cf_parse_u64 },
632 { sizeof(double), cf_parse_double },
633 { sizeof(u32), cf_parse_ip },
634 { sizeof(byte*), cf_parse_string },
635 { sizeof(int), NULL }, // lookups are parsed extra
636 { 0, NULL }, // user-defined types are parsed extra
640 type_size(enum cf_type type, struct cf_user_type *utype)
643 return parsers[type].size;
649 cf_parse_ary(uns number, byte **pars, void *ptr, enum cf_type type, union cf_union *u)
651 for (uns i=0; i<number; i++)
654 uns size = type_size(type, u->utype);
655 if (type < CT_LOOKUP)
656 msg = ((cf_basic_parser*) parsers[type].parser) (pars[i], ptr + i * size);
657 else if (type == CT_LOOKUP)
658 msg = cf_parse_lookup(pars[i], ptr + i * size, u->lookup);
659 else if (type == CT_USER)
660 msg = u->utype->parser(pars[i], ptr + i * size);
664 return cf_printf("Cannot parse item %d: %s", i+1, msg);
672 static byte *op_names[] = { CF_OPERATIONS };
675 #define OP_MASK 0xff // only get the operation
676 #define OP_OPEN 0x100 // here we only get an opening brace instead of parameters
677 #define OP_1ST 0x200 // in the 1st phase selectors are recorded into the mask
678 #define OP_2ND 0x400 // in the 2nd phase real data are entered
681 interpret_set_dynamic(struct cf_item *item, int number, byte **pars, void **ptr)
683 enum cf_type type = item->type;
684 cf_journal_block(ptr, sizeof(void*));
685 // boundary checks done by the caller
686 uns size = type_size(item->type, item->u.utype);
687 ASSERT(size >= sizeof(uns));
688 *ptr = cf_malloc((number+1) * size) + size;
689 * (uns*) (*ptr - size) = number;
690 return cf_parse_ary(number, pars, *ptr, type, &item->u);
694 interpret_add_dynamic(struct cf_item *item, int number, byte **pars, int *processed, void **ptr, enum cf_operation op)
696 enum cf_type type = item->type;
698 uns size = type_size(item->type, item->u.utype);
699 ASSERT(size >= sizeof(uns));
700 int old_nr = old_p ? * (int*) (old_p - size) : 0;
701 int taken = MIN(number, ABS(item->number)-old_nr);
703 // stretch the dynamic array
704 void *new_p = cf_malloc((old_nr + taken + 1) * size) + size;
705 * (uns*) (new_p - size) = old_nr + taken;
706 cf_journal_block(ptr, sizeof(void*));
708 if (op == OP_APPEND) {
709 memcpy(new_p, old_p, old_nr * size);
710 return cf_parse_ary(taken, pars, new_p + old_nr * size, type, &item->u);
711 } else if (op == OP_PREPEND) {
712 memcpy(new_p + taken * size, old_p, old_nr * size);
713 return cf_parse_ary(taken, pars, new_p, type, &item->u);
715 return cf_printf("Dynamic arrays do not support operation %s", op_names[op]);
718 static byte *interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic);
721 interpret_section(struct cf_section *sec, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
725 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
728 byte *msg = interpret_set_item(ci, number, pars, &taken, ptr + (addr_int_t) ci->ptr, allow_dynamic && !ci[1].cls);
730 return cf_printf("Item %s: %s", ci->name, msg);
734 if (!number) // stop parsing, because many parsers would otherwise complain that number==0
741 add_to_list(cnode *where, cnode *new_node, enum cf_operation op)
745 case OP_EDIT: // edition has been done in-place
748 CF_JOURNAL_VAR(where->prev->next);
749 CF_JOURNAL_VAR(where->next->prev);
752 case OP_AFTER: // implementation dependend (prepend_head = after(list)), and where==list, see clists.h:74
755 CF_JOURNAL_VAR(where->next->prev);
756 CF_JOURNAL_VAR(where->next);
757 clist_insert_after(new_node, where);
759 case OP_BEFORE: // implementation dependend (append_tail = before(list))
762 CF_JOURNAL_VAR(where->prev->next);
763 CF_JOURNAL_VAR(where->prev);
764 clist_insert_before(new_node, where);
772 interpret_add_list(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, enum cf_operation op)
775 return cf_printf("You have to open a block for operation %s", op_names[op]);
777 return "Nothing to add to the list";
778 struct cf_section *sec = item->u.sec;
782 void *node = cf_malloc(sec->size);
783 cf_init_section(item->name, sec, node, 1);
784 add_to_list(ptr, node, op);
786 /* If the node contains any dynamic attribute at the end, we suppress
787 * auto-repetition here and pass the flag inside instead. */
788 TRY( interpret_section(sec, number, pars, &taken, node, sec->flags & SEC_FLAG_DYNAMIC) );
792 if (sec->flags & SEC_FLAG_DYNAMIC)
799 interpret_set_item(struct cf_item *item, int number, byte **pars, int *processed, void *ptr, uns allow_dynamic)
806 return "Missing value";
807 taken = MIN(number, item->number);
809 uns size = type_size(item->type, item->u.utype);
810 cf_journal_block(ptr, taken * size);
811 return cf_parse_ary(taken, pars, ptr, item->type, &item->u);
814 return "Dynamic array cannot be used here";
815 taken = MIN(number, ABS(item->number));
817 return interpret_set_dynamic(item, taken, pars, ptr);
819 if (item->number < 0 && !allow_dynamic)
820 return "Parsers with variable number of parameters cannot be used here";
821 if (item->number > 0 && number < item->number)
822 return "Not enough parameters available for the parser";
823 taken = MIN(number, ABS(item->number));
825 for (int i=0; i<taken; i++)
826 pars[i] = cf_strdup(pars[i]);
827 return item->u.par(taken, pars, ptr);
829 return interpret_section(item->u.sec, number, pars, processed, ptr, allow_dynamic);
832 return "Lists cannot be used here";
833 return interpret_add_list(item, number, pars, processed, ptr, OP_SET);
840 interpret_clear(struct cf_item *item, void *ptr)
842 if (item->cls == CC_LIST) {
843 cf_journal_block(ptr, sizeof(clist));
845 } else if (item->cls == CC_DYNAMIC) {
846 cf_journal_block(ptr, sizeof(void *));
847 * (void**) ptr = NULL;
849 return "The item is not a list or a dynamic array";
854 cmp_items(void *i1, void *i2, struct cf_item *item)
856 ASSERT(item->cls == CC_STATIC);
857 i1 += (addr_int_t) item->ptr;
858 i2 += (addr_int_t) item->ptr;
859 if (item->type == CT_STRING)
860 return strcmp(* (byte**) i1, * (byte**) i2);
861 else // all numeric types
862 return memcmp(i1, i2, type_size(item->type, item->u.utype));
866 find_list_node(clist *list, void *query, struct cf_section *sec, u32 mask)
868 CLIST_FOR_EACH(cnode *, n, *list)
871 for (uns i=0; i<32; i++)
873 if (cmp_items(n, query, sec->cfg+i))
885 record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
887 uns nr = sec->flags & SEC_FLAG_NUMBER;
888 if (item >= sec->cfg && item < sec->cfg + nr) // setting an attribute relative to this section
890 uns i = item - sec->cfg;
892 return "Cannot select list nodes by this attribute";
893 if (sec->cfg[i].cls != CC_STATIC)
894 return "Selection can only be done based on basic attributes";
900 #define MAX_STACK_SIZE 100
901 static struct item_stack {
902 struct cf_section *sec; // nested section
903 void *base_ptr; // because original pointers are often relative
904 enum cf_operation op; // it is performed when a closing brace is encountered
905 void *list; // list the operations should be done on
906 u32 mask; // bit array of selectors searching in a list
907 struct cf_item *item; // cf_item of the list
908 } stack[MAX_STACK_SIZE];
912 opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
914 if (level >= MAX_STACK_SIZE-1)
915 return "Too many nested sections";
916 stack[++level] = (struct item_stack) {
924 if (!item) // unknown is ignored; we just need to trace recursion
926 stack[level].sec = item->u.sec;
927 if (item->cls == CC_SECTION)
929 stack[level].base_ptr = ptr;
930 stack[level].op = OP_EDIT | OP_2ND; // this list operation does nothing
932 else if (item->cls == CC_LIST)
934 stack[level].base_ptr = cf_malloc(item->u.sec->size);
935 cf_init_section(item->name, item->u.sec, stack[level].base_ptr, 1);
936 stack[level].list = ptr;
937 stack[level].item = item;
938 if ((op & OP_MASK) < OP_REMOVE) {
939 add_to_list(ptr, stack[level].base_ptr, op & OP_MASK);
940 stack[level].op |= OP_2ND;
942 stack[level].op |= OP_1ST;
945 return "Opening brace can only be used on sections and lists";
950 closing_brace(struct item_stack *st, enum cf_operation op, int number, byte **pars)
952 if (st->op == OP_CLOSE) // top-level
953 return "Unmatched } parenthesis";
954 if (!st->sec) { // dummy run on unknown section
959 enum cf_operation pure_op = st->op & OP_MASK;
962 st->list = find_list_node(st->list, st->base_ptr, st->sec, st->mask);
964 return "Cannot find a node matching the query";
965 if (pure_op != OP_REMOVE)
967 if (pure_op == OP_EDIT)
968 st->base_ptr = st->list;
969 else if (pure_op == OP_AFTER || pure_op == OP_BEFORE)
970 cf_init_section(st->item->name, st->sec, st->base_ptr, 1);
971 else if (pure_op == OP_COPY) {
972 if (st->sec->flags & SEC_FLAG_CANT_COPY)
973 return cf_printf("Item %s cannot be copied", st->item->name);
974 memcpy(st->base_ptr, st->list, st->sec->size); // strings and dynamic arrays are shared
976 TRY( st->sec->copy(st->base_ptr, st->list) );
979 if (op & OP_OPEN) { // stay at the same recursion level
980 st->op = (st->op | OP_2ND) & ~OP_1ST;
981 add_to_list(st->list, st->base_ptr, pure_op);
984 int taken; // parse parameters on 1 line immediately
985 TRY( interpret_section(st->sec, number, pars, &taken, st->base_ptr, 1) );
988 // and fall-thru to the 2nd phase
990 add_to_list(st->list, st->base_ptr, pure_op);
994 return "No parameters expected after the }";
995 else if (op & OP_OPEN)
996 return "No { is expected";
1002 interpret_line(byte *name, enum cf_operation op, int number, byte **pars)
1005 if ((op & OP_MASK) == OP_CLOSE)
1006 return closing_brace(stack+level, op, number, pars);
1007 void *ptr = stack[level].base_ptr;
1008 struct cf_item *item = find_item(stack[level].sec, name, &msg, &ptr);
1011 if (stack[level].op & OP_1ST)
1012 TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
1013 if (op & OP_OPEN) { // the operation will be performed after the closing brace
1015 return "Cannot open a block after a parameter has been passed on a line";
1016 return opening_brace(item, ptr, op);
1018 if (!item) // ignored item in an unknown section
1022 int taken; // process as many parameters as possible
1024 taken = 0, msg = interpret_clear(item, ptr);
1025 else if (op == OP_SET)
1026 msg = interpret_set_item(item, number, pars, &taken, ptr, 1);
1027 else if (item->cls == CC_DYNAMIC)
1028 msg = interpret_add_dynamic(item, number, pars, &taken, ptr, op);
1029 else if (item->cls == CC_LIST)
1030 msg = interpret_add_list(item, number, pars, &taken, ptr, op);
1032 return cf_printf("Operation %s not supported on attribute %s", op_names[op], name);
1036 return cf_printf("Too many parameters: %d>%d", number, taken);
1042 cf_write_item(struct cf_item *item, enum cf_operation op, int number, byte **pars)
1048 msg = interpret_set_item(item, number, pars, &taken, item->ptr, 1);
1052 msg = interpret_clear(item, item->ptr);
1056 if (item->cls == CC_DYNAMIC)
1057 msg = interpret_add_dynamic(item, number, pars, &taken, item->ptr, op);
1058 else if (item->cls == CC_LIST)
1059 msg = interpret_add_list(item, number, pars, &taken, item->ptr, op);
1061 return "The attribute class does not support append/prepend";
1064 return "Unsupported operation";
1069 return "Too many parameters";
1078 stack[0] = (struct item_stack) {
1088 static uns postpone_commit; // only for cf_getopt()
1094 log(L_ERROR, "Unterminated block");
1098 if (postpone_commit)
1100 if (commit_section(§ions, NULL, !everything_committed))
1102 everything_committed = 1;
1110 if (postpone_commit) {
1111 postpone_commit = 0;
1113 die("Cannot commit after the initialization");
1117 /* Text file parser */
1119 static byte *name_parse_fb;
1120 static struct fastbuf *parse_fb;
1121 static uns line_num;
1123 #define MAX_LINE 4096
1124 static byte line_buf[MAX_LINE];
1125 static byte *line = line_buf;
1127 #include "lib/bbuf.h"
1128 static bb_t copy_buf;
1131 #define GBUF_TYPE uns
1132 #define GBUF_PREFIX(x) split_##x
1133 #include "lib/gbuf.h"
1134 static split_t word_buf;
1136 static uns ends_by_brace; // the line is ended by "{"
1141 if (!bgets(parse_fb, line_buf, MAX_LINE))
1145 while (Cblank(*line))
1151 append(byte *start, byte *end)
1153 uns len = end - start;
1154 bb_grow(©_buf, copied + len + 1);
1155 memcpy(copy_buf.ptr + copied, start, len);
1157 copy_buf.ptr[copied-1] = 0;
1160 #define CONTROL_CHAR(x) (x == '{' || x == '}' || x == ';')
1161 // these characters separate words like blanks
1164 get_word(uns is_command_name)
1166 if (*line == '\'') {
1170 while (*line && *line != '\'')
1172 append(start, line);
1175 copy_buf.ptr[copied-1] = '\n';
1177 return "Unterminated apostrophe word at the end";
1181 } else if (*line == '"') {
1183 uns start_copy = copied;
1188 if (*line == '"' && !escape)
1190 else if (*line == '\\')
1196 append(start, line);
1200 copy_buf.ptr[copied-1] = '\n';
1201 else // merge two lines
1204 return "Unterminated quoted word at the end";
1208 byte *tmp = stk_str_unesc(copy_buf.ptr + start_copy);
1209 uns l = strlen(tmp);
1210 bb_grow(©_buf, start_copy + l + 1);
1211 strcpy(copy_buf.ptr + start_copy, tmp);
1212 copied = start_copy + l + 1;
1215 // promised that *line is non-null and non-blank
1217 while (*line && !Cblank(*line) && !CONTROL_CHAR(*line)
1218 && (*line != '=' || !is_command_name))
1220 if (*line == '=') { // nice for setting from a command-line
1222 return "Assignment without a variable";
1225 if (line == start) // already the first char is control
1227 append(start, line);
1229 while (Cblank(*line))
1235 get_token(uns is_command_name, byte **msg)
1239 if (!*line || *line == '#') {
1240 if (!is_command_name || !get_line())
1242 } else if (*line == ';') {
1244 if (!is_command_name || *msg)
1246 } else if (*line == '\\' && !line[1]) {
1248 *msg = "Last line ends by a backslash";
1251 if (!*line || *line == '#')
1252 log(L_WARN, "The line %s:%d following a backslash is empty", name_parse_fb, line_num);
1254 split_grow(&word_buf, words+1);
1256 word_buf.ptr[words++] = copied;
1257 *msg = get_word(is_command_name);
1258 return *msg ? NULL : copy_buf.ptr + start;
1266 words = copied = ends_by_brace = 0;
1267 byte *msg, *start_word;
1268 if (!(start_word = get_token(1, &msg)))
1270 if (*start_word == '{') // only one opening brace
1271 return "Unexpected opening brace";
1272 while (*line != '}') // stays for the next time
1274 if (!(start_word = get_token(0, &msg)))
1276 if (*start_word == '{') {
1277 words--; // discard the brace
1285 /* Parsing multiple files */
1288 parse_fastbuf(byte *name_fb, struct fastbuf *fb, uns depth)
1291 name_parse_fb = name_fb;
1298 msg = split_command();
1303 byte *name = copy_buf.ptr + word_buf.ptr[0];
1304 byte *pars[words-1];
1305 for (uns i=1; i<words; i++)
1306 pars[i-1] = copy_buf.ptr + word_buf.ptr[i];
1307 if (!strcasecmp(name, "include"))
1310 msg = "Expecting one filename";
1312 msg = "Too many nested files";
1313 else if (*line && *line != '#') // because the contents of line_buf is not re-entrant and will be cleared
1314 msg = "The input command must be the last one on a line";
1317 struct fastbuf *new_fb = bopen_try(pars[0], O_RDONLY, 1<<14);
1319 msg = cf_printf("Cannot open file %s: %m", pars[0]);
1323 msg = parse_fastbuf(stk_strdup(pars[0]), new_fb, depth+1);
1331 enum cf_operation op;
1332 byte *c = strchr(name, ':');
1334 op = strcmp(name, "}") ? OP_SET : OP_CLOSE;
1337 switch (Clocase(*c)) {
1338 case 's': op = OP_SET; break;
1339 case 'c': op = Clocase(c[1]) == 'l' ? OP_CLEAR: OP_COPY; break;
1340 case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
1341 case 'p': op = OP_PREPEND; break;
1342 case 'r': op = OP_REMOVE; break;
1343 case 'e': op = OP_EDIT; break;
1344 case 'b': op = OP_BEFORE; break;
1345 default: op = OP_SET; break;
1347 if (strcasecmp(c, op_names[op])) {
1348 msg = cf_printf("Unknown operation %s", c);
1354 msg = interpret_line(name, op, words-1, pars);
1359 log(L_ERROR, "File %s, line %d: %s", name_fb, line_num, msg);
1360 return "included from here";
1363 #ifndef DEFAULT_CONFIG
1364 #define DEFAULT_CONFIG NULL
1366 byte *cf_def_file = DEFAULT_CONFIG;
1369 load_file(byte *file)
1372 struct fastbuf *fb = bopen_try(file, O_RDONLY, 1<<14);
1374 log(L_ERROR, "Cannot open %s: %m", file);
1377 byte *msg = parse_fastbuf(file, fb, 0);
1379 int err = !!msg || done_stack();
1386 load_string(byte *string)
1390 fbbuf_init_read(&fb, string, strlen(string), 0);
1391 byte *msg = parse_fastbuf("memory string", &fb, 0);
1392 return !!msg || done_stack();
1395 /* Command-line parser */
1401 if (cf_load(cf_def_file))
1402 die("Cannot load default config %s", cf_def_file);
1406 cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index)
1408 static int other_options = 0;
1410 int res = getopt_long (argc, argv, short_opts, long_opts, long_index);
1411 if (res == 'S' || res == 'C' || res == 0x64436667)
1414 die("The -S and -C options must precede all other arguments");
1416 postpone_commit = 1;
1419 die("Cannot set %s", optarg);
1420 } else if (res == 'C') {
1421 postpone_commit = 1;
1422 if (cf_load(optarg))
1423 die("Cannot load config file %s", optarg);
1426 else { /* --dumpconfig */
1429 struct fastbuf *b = bfdopen(1, 4096);
1430 cf_dump_sections(b);
1436 /* unhandled option or end of options */
1437 if (res != ':' && res != '?')
1449 spaces(struct fastbuf *fb, uns nr)
1451 for (uns i=0; i<nr; i++)
1456 dump_basic(struct fastbuf *fb, void *ptr, enum cf_type type, union cf_union *u)
1459 case CT_INT: bprintf(fb, "%d ", *(uns*)ptr); break;
1460 case CT_U64: bprintf(fb, "%llu ", *(u64*)ptr); break;
1461 case CT_DOUBLE: bprintf(fb, "%lg ", *(double*)ptr); break;
1462 case CT_IP: bprintf(fb, "%08x ", *(uns*)ptr); break;
1465 bprintf(fb, "'%s' ", *(byte**)ptr);
1467 bprintf(fb, "NULL ");
1469 case CT_LOOKUP: bprintf(fb, "%s ", *(int*)ptr >= 0 ? u->lookup[ *(int*)ptr ] : (byte*) "???"); break;
1471 if (u->utype->dumper)
1472 u->utype->dumper(fb, ptr);
1474 bprintf(fb, "??? ");
1479 static void dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr);
1481 static byte *class_names[] = { "end", "static", "dynamic", "parser", "section", "list" };
1482 static byte *type_names[] = { "int", "u64", "double", "ip", "string", "lookup", "user" };
1485 dump_item(struct fastbuf *fb, struct cf_item *item, int level, void *ptr)
1487 ptr += (addr_int_t) item->ptr;
1488 enum cf_type type = item->type;
1489 uns size = type_size(item->type, item->u.utype);
1492 bprintf(fb, "%s: C%s #", item->name, class_names[item->cls]);
1493 if (item->number == CF_ANY_NUM)
1496 bprintf(fb, "%d ", item->number);
1497 if (item->cls == CC_STATIC || item->cls == CC_DYNAMIC) {
1498 bprintf(fb, "T%s ", type_names[type]);
1499 if (item->type == CT_USER)
1500 bprintf(fb, "U%s S%d ", item->u.utype->name, size);
1502 if (item->cls == CC_STATIC) {
1503 for (i=0; i<item->number; i++)
1504 dump_basic(fb, ptr + i * size, type, &item->u);
1505 } else if (item->cls == CC_DYNAMIC) {
1506 ptr = * (void**) ptr;
1508 int real_nr = * (int*) (ptr - size);
1509 bprintf(fb, "N%d ", real_nr);
1510 for (i=0; i<real_nr; i++)
1511 dump_basic(fb, ptr + i * size, type, &item->u);
1513 bprintf(fb, "NULL ");
1516 if (item->cls == CC_SECTION)
1517 dump_section(fb, item->u.sec, level+1, ptr);
1518 else if (item->cls == CC_LIST) {
1520 CLIST_FOR_EACH(cnode *, n, * (clist*) ptr) {
1521 spaces(fb, level+1);
1522 bprintf(fb, "item %d\n", ++idx);
1523 dump_section(fb, item->u.sec, level+2, n);
1529 dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr)
1532 bprintf(fb, "S%d F%x:\n", sec->size, sec->flags);
1533 for (struct cf_item *item=sec->cfg; item->cls; item++)
1534 dump_item(fb, item, level, ptr);
1538 cf_dump_sections(struct fastbuf *fb)
1540 dump_section(fb, §ions, 0, NULL);
1544 * - more space efficient journal