X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fconf-parser.c;h=a71dcd0d8fb8c87460ea24f81b244334ce740519;hp=df3584dd04567bbc73272b2aebb6dd56c81803a1;hb=de7b95cdc3228131498021c2fdcf6647004c3920;hpb=3dab29438c431f8e068c079af13ed26a81e563d3 diff --git a/src/conf-parser.c b/src/conf-parser.c index df3584dd0..a71dcd0d8 100644 --- a/src/conf-parser.c +++ b/src/conf-parser.c @@ -1,4 +1,4 @@ -/*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd. @@ -31,52 +31,140 @@ #include "strv.h" #include "log.h" -#define COMMENTS "#;\n" +int config_item_table_lookup( + void *table, + const char *section, + const char *lvalue, + ConfigParserCallback *func, + int *ltype, + void **data, + void *userdata) { + + ConfigTableItem *t; + + assert(table); + assert(lvalue); + assert(func); + assert(ltype); + assert(data); + + for (t = table; t->lvalue; t++) { + + if (!streq(lvalue, t->lvalue)) + continue; + + if (!streq_ptr(section, t->section)) + continue; + + *func = t->parse; + *ltype = t->ltype; + *data = t->data; + return 1; + } + + return 0; +} + +int config_item_perf_lookup( + void *table, + const char *section, + const char *lvalue, + ConfigParserCallback *func, + int *ltype, + void **data, + void *userdata) { + + ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; + const ConfigPerfItem *p; + + assert(table); + assert(lvalue); + assert(func); + assert(ltype); + assert(data); + + if (!section) + p = lookup(lvalue, strlen(lvalue)); + else { + char *key; + + key = join(section, ".", lvalue, NULL); + if (!key) + return -ENOMEM; + + p = lookup(key, strlen(key)); + free(key); + } + + if (!p) + return 0; + + *func = p->parse; + *ltype = p->ltype; + *data = (uint8_t*) userdata + p->offset; + return 1; +} /* Run the user supplied parser for an assignment */ static int next_assignment( const char *filename, unsigned line, + ConfigItemLookup lookup, + void *table, const char *section, - const ConfigItem *t, - bool relaxed, const char *lvalue, const char *rvalue, + bool relaxed, void *userdata) { + ConfigParserCallback func = NULL; + int ltype = 0; + void *data = NULL; + int r; + assert(filename); - assert(t); + assert(line > 0); + assert(lookup); assert(lvalue); assert(rvalue); - for (; t->parse || t->lvalue; t++) { - - if (t->lvalue && !streq(lvalue, t->lvalue)) - continue; - - if (t->section && !section) - continue; - - if (t->section && !streq(section, t->section)) - continue; + r = lookup(table, section, lvalue, &func, <ype, &data, userdata); + if (r < 0) + return r; - if (!t->parse) - return 0; + if (r > 0) { + if (func) + return func(filename, line, section, lvalue, ltype, rvalue, data, userdata); - return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata); + return 0; } /* Warn about unknown non-extension fields. */ if (!relaxed && !startswith(lvalue, "X-")) - log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section)); + log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section); return 0; } /* Parse a variable assignment line */ -static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, bool relaxed, char *l, void *userdata) { +static int parse_line( + const char *filename, + unsigned line, + const char *sections, + ConfigItemLookup lookup, + void *table, + bool relaxed, + char **section, + char *l, + void *userdata) { + char *e; + assert(filename); + assert(line > 0); + assert(lookup); + assert(l); + l = strstrip(l); if (!*l) @@ -89,10 +177,11 @@ static int parse_line(const char *filename, unsigned line, char **section, const char *fn; int r; - if (!(fn = file_in_same_dir(filename, strstrip(l+9)))) + fn = file_in_same_dir(filename, strstrip(l+9)); + if (!fn) return -ENOMEM; - r = config_parse(fn, NULL, sections, t, relaxed, userdata); + r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata); free(fn); return r; @@ -110,22 +199,30 @@ static int parse_line(const char *filename, unsigned line, char **section, const return -EBADMSG; } - if (!(n = strndup(l+1, k-2))) + n = strndup(l+1, k-2); + if (!n) return -ENOMEM; - if (!relaxed && sections && !strv_contains((char**) sections, n)) - log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n); + if (sections && !nulstr_contains(sections, n)) { + + if (!relaxed) + log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n); - free(*section); - *section = n; + free(n); + *section = NULL; + } else { + free(*section); + *section = n; + } return 0; } - if (sections && !strv_contains((char**) sections, *section)) + if (sections && !*section) return 0; - if (!(e = strchr(l, '='))) { + e = strchr(l, '='); + if (!e) { log_error("[%s:%u] Missing '='.", filename, line); return -EBADMSG; } @@ -133,11 +230,28 @@ static int parse_line(const char *filename, unsigned line, char **section, const *e = 0; e++; - return next_assignment(filename, line, *section, t, relaxed, strstrip(l), strstrip(e), userdata); + return next_assignment( + filename, + line, + lookup, + table, + *section, + strstrip(l), + strstrip(e), + relaxed, + userdata); } /* Go through the file and parse each line */ -int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, bool relaxed, void *userdata) { +int config_parse( + const char *filename, + FILE *f, + const char *sections, + ConfigItemLookup lookup, + void *table, + bool relaxed, + void *userdata) { + unsigned line = 0; char *section = NULL; int r; @@ -145,10 +259,11 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co char *continuation = NULL; assert(filename); - assert(t); + assert(lookup); if (!f) { - if (!(f = fopen(filename, "re"))) { + f = fopen(filename, "re"); + if (!f) { r = -errno; log_error("Failed to open configuration file '%s': %s", filename, strerror(-r)); goto finish; @@ -173,7 +288,8 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co truncate_nl(l); if (continuation) { - if (!(c = strappend(continuation, l))) { + c = strappend(continuation, l); + if (!c) { r = -ENOMEM; goto finish; } @@ -196,15 +312,26 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co if (c) continuation = c; - else if (!(continuation = strdup(l))) { - r = -ENOMEM; - goto finish; + else { + continuation = strdup(l); + if (!continuation) { + r = -ENOMEM; + goto finish; + } } continue; } - r = parse_line(filename, ++line, §ion, sections, t, relaxed, p, userdata); + r = parse_line(filename, + ++line, + sections, + lookup, + table, + relaxed, + §ion, + p, + userdata); free(c); if (r < 0) @@ -228,6 +355,7 @@ int config_parse_int( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -241,8 +369,60 @@ int config_parse_int( assert(data); if ((r = safe_atoi(rvalue, i)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; + log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +int config_parse_long( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + long *i = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if ((r = safe_atoli(rvalue, i)) < 0) { + log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +int config_parse_uint64( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + uint64_t *u = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if ((r = safe_atou64(rvalue, u)) < 0) { + log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); + return 0; } return 0; @@ -253,6 +433,7 @@ int config_parse_unsigned( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -278,6 +459,7 @@ int config_parse_size( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -292,8 +474,8 @@ int config_parse_size( assert(data); if ((r = safe_atou(rvalue, &u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; + log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); + return 0; } *sz = (size_t) u; @@ -305,6 +487,7 @@ int config_parse_bool( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -318,8 +501,8 @@ int config_parse_bool( assert(data); if ((k = parse_boolean(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); - return k; + log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue); + return 0; } *b = !!k; @@ -331,6 +514,7 @@ int config_parse_string( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -360,6 +544,7 @@ int config_parse_path( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -373,8 +558,8 @@ int config_parse_path( assert(data); if (!path_is_absolute(rvalue)) { - log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue); - return -EINVAL; + log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); + return 0; } if (!(n = strdup(rvalue))) @@ -393,6 +578,7 @@ int config_parse_strv( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -423,7 +609,7 @@ int config_parse_strv( k = 0; FOREACH_WORD_QUOTED(w, l, rvalue, state) - if (!(n[k++] = strndup(w, l))) + if (!(n[k++] = cunescape_length(w, l))) goto fail; n[k] = NULL; @@ -445,6 +631,7 @@ int config_parse_path_strv( unsigned line, const char *section, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata) { @@ -475,15 +662,15 @@ int config_parse_path_strv( n[k] = (*sv)[k]; FOREACH_WORD_QUOTED(w, l, rvalue, state) { - if (!(n[k] = strndup(w, l))) { + if (!(n[k] = cunescape_length(w, l))) { r = -ENOMEM; goto fail; } if (!path_is_absolute(n[k])) { - log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue); - r = -EINVAL; - goto fail; + log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); + free(n[k]); + continue; } path_kill_slashes(n[k]); @@ -505,3 +692,63 @@ fail: return r; } + +int config_parse_usec( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + usec_t *usec = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (parse_usec(rvalue, usec) < 0) { + log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +int config_parse_mode( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + mode_t *m = data; + long l; + char *x = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + errno = 0; + l = strtol(rvalue, &x, 8); + if (!x || *x || errno) { + log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue); + return 0; + } + + if (l < 0000 || l > 07777) { + log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue); + return 0; + } + + *m = (mode_t) l; + return 0; +}