X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=support%2Fnfs%2Fconffile.c;h=5015e945691a7c513700c093c0f37b76a2b7532b;hp=a8b803758f85c2f58d196bb2643874a2371ddb61;hb=3ce15aeaa66a2f523c6fa92bfe818734bdedfcea;hpb=c6a270ea8ab6ad299e6a43445420f22e0c617e3e diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c index a8b8037..5015e94 100644 --- a/support/nfs/conffile.c +++ b/support/nfs/conffile.c @@ -49,13 +49,18 @@ #include "conffile.h" #include "xlog.h" -static void conf_load_defaults (int); +#pragma GCC visibility push(hidden) + +static void conf_load_defaults(void); +static int conf_set(int , char *, char *, char *, + char *, int , int ); struct conf_trans { TAILQ_ENTRY (conf_trans) link; int trans; enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; char *section; + char *arg; char *tag; char *value; int override; @@ -93,6 +98,7 @@ static const u_int8_t asc2bin[] = struct conf_binding { LIST_ENTRY (conf_binding) link; char *section; + char *arg; char *tag; char *value; int is_default; @@ -115,18 +121,6 @@ conf_hash(char *s) return hash; } -/* - * Convert letter from upper case to lower case - */ -static inline void upper2lower(char *str) -{ - char *ptr = str; - - while (*ptr) - *ptr++ = tolower(*ptr); -} - - /* * Insert a tag-value combination from LINE (the equal sign is at POS) */ @@ -143,6 +137,7 @@ conf_remove_now(char *section, char *tag) LIST_REMOVE(cb, link); xlog(LOG_INFO,"[%s]:%s->%s removed", section, tag, cb->value); free(cb->section); + free(cb->arg); free(cb->tag); free(cb->value); free(cb); @@ -166,6 +161,7 @@ conf_remove_section_now(char *section) LIST_REMOVE(cb, link); xlog(LOG_INFO, "[%s]:%s->%s removed", section, cb->tag, cb->value); free(cb->section); + free(cb->arg); free(cb->tag); free(cb->value); free(cb); @@ -179,27 +175,28 @@ conf_remove_section_now(char *section) * into SECTION of our configuration database. */ static int -conf_set_now(char *section, char *tag, char *value, int override, - int is_default) +conf_set_now(char *section, char *arg, char *tag, + char *value, int override, int is_default) { struct conf_binding *node = 0; if (override) conf_remove_now(section, tag); - else if (conf_get_str(section, tag)) { + else if (conf_get_section(section, arg, tag)) { if (!is_default) { xlog(LOG_INFO, "conf_set: duplicate tag [%s]:%s, ignoring...\n", section, tag); } return 1; } - node = calloc(1, sizeof *node); if (!node) { xlog_warn("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node); return 1; } node->section = strdup(section); + if (arg) + node->arg = strdup(arg); node->tag = strdup(tag); node->value = strdup(value); node->is_default = is_default; @@ -215,17 +212,15 @@ conf_set_now(char *section, char *tag, char *value, int override, static void conf_parse_line(int trans, char *line, size_t sz) { - char *val; - size_t i; - int j; + char *val, *ptr; + size_t i, valsize; + size_t j; static char *section = 0; + static char *arg = 0; static int ln = 0; /* Lines starting with '#' or ';' are comments. */ ln++; - if (*line == '#' || *line == ';') - return; - /* Ignore blank lines */ if (*line == '\0') return; @@ -234,13 +229,15 @@ conf_parse_line(int trans, char *line, size_t sz) while (isblank(*line)) line++; + if (*line == '#' || *line == ';') + return; + /* '[section]' parsing... */ if (*line == '[') { line++; /* Strip off any blanks after '[' */ while (isblank(*line)) line++; - for (i = 0; i < sz; i++) { if (line[i] == ']') { break; @@ -249,25 +246,46 @@ conf_parse_line(int trans, char *line, size_t sz) if (section) free(section); if (i == sz) { - xlog_warn("conf_parse_line: %d:" + xlog_warn("config file error: line %d: " "non-matched ']', ignoring until next section", ln); section = 0; return; } /* Strip off any blanks before ']' */ val = line; + j=0; while (*val && !isblank(*val)) val++, j++; if (*val) i = j; - - section = malloc(i); + section = malloc(i+1); if (!section) { xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, (unsigned long)i); return; } strncpy(section, line, i); + section[i] = '\0'; + + if (arg) + free(arg); + arg = 0; + + ptr = strchr(val, '"'); + if (ptr == NULL) + return; + line = ++ptr; + while (*ptr && *ptr != '"' && *ptr != ']') + ptr++; + if (*ptr == '\0' || *ptr == ']') { + xlog_warn("config file error: line %d: " + "non-matched '\"', ignoring until next section", ln); + } else { + *ptr = '\0'; + arg = strdup(line); + if (!arg) + xlog_warn("conf_parse_line: %d: malloc arg failed", ln); + } return; } @@ -276,24 +294,31 @@ conf_parse_line(int trans, char *line, size_t sz) if (line[i] == '=') { /* If no section, we are ignoring the lines. */ if (!section) { - xlog_warn("conf_parse_line: %d: ignoring line due to no section", - ln); + xlog_warn("config file error: line %d: " + "ignoring line due to no section", ln); return; } line[strcspn (line, " \t=")] = '\0'; val = line + i + 1 + strspn (line + i + 1, " \t"); - /* Skip trailing whitespace, if any */ - for (j = sz - (val - line) - 1; j > 0 && isspace(val[j]); j--) - val[j] = '\0'; + valsize = 0; + while (val[valsize++]); + + /* Skip trailing spaces and comments */ + for (j = 0; j < valsize; j++) { + if (val[j] == '#' || val[j] == ';' || isspace(val[j])) { + val[j] = '\0'; + break; + } + } /* XXX Perhaps should we not ignore errors? */ - conf_set(trans, section, line, val, 0, 0); + conf_set(trans, section, arg, line, val, 0, 0); return; } } /* Other non-empty lines are weird. */ i = strspn(line, " \t"); if (line[i]) - xlog_warn("conf_parse_line: %d: syntax error", ln); + xlog_warn("config file error: line %d:", ln); return; } @@ -325,7 +350,7 @@ conf_parse(int trans, char *buf, size_t sz) } static void -conf_load_defaults(int tr) +conf_load_defaults(void) { /* No defaults */ return; @@ -384,7 +409,7 @@ conf_reinit(void) trans = conf_begin(); /* Load default configuration values. */ - conf_load_defaults(trans); + conf_load_defaults(); /* Free potential existing configuration. */ if (conf_addr) { @@ -460,6 +485,26 @@ conf_get_str(char *section, char *tag) } return 0; } +/* + * Find a section that may or may not have an argument + */ +char * +conf_get_section(char *section, char *arg, char *tag) +{ + struct conf_binding *cb; + + cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); + for (; cb; cb = LIST_NEXT (cb, link)) { + if (strcasecmp(section, cb->section) != 0) + continue; + if (arg && strcasecmp(arg, cb->arg) != 0) + continue; + if (strcasecmp(tag, cb->tag) != 0) + continue; + return cb->value; + } + return 0; +} /* * Build a list of string values out of the comma separated value denoted by @@ -652,9 +697,9 @@ conf_trans_node(int transaction, enum conf_op op) } /* Queue a set operation. */ -int -conf_set(int transaction, char *section, char *tag, - char *value, int override, int is_default) +static int +conf_set(int transaction, char *section, char *arg, + char *tag, char *value, int override, int is_default) { struct conf_trans *node; @@ -669,6 +714,15 @@ conf_set(int transaction, char *section, char *tag, /* Make Section names case-insensitive */ upper2lower(node->section); + if (arg) { + node->arg = strdup(arg); + if (!node->arg) { + xlog_warn("conf_set: strdup(\"%s\") failed", arg); + goto fail; + } + } else + node->arg = NULL; + node->tag = strdup(tag); if (!node->tag) { xlog_warn("conf_set: strdup(\"%s\") failed", tag); @@ -756,8 +810,9 @@ conf_end(int transaction, int commit) if (commit) { switch (node->op) { case CONF_SET: - conf_set_now(node->section, node->tag, node->value, - node->override, node->is_default); + conf_set_now(node->section, node->arg, + node->tag, node->value, node->override, + node->is_default); break; case CONF_REMOVE: conf_remove_now(node->section, node->tag); @@ -813,8 +868,9 @@ void conf_report (void) { struct conf_binding *cb, *last = 0; - unsigned int i, len; + unsigned int i, len, diff_arg = 0; char *current_section = (char *)0; + char *current_arg = (char *)0; struct dumper *dumper, *dnode; dumper = dnode = (struct dumper *)calloc(1, sizeof *dumper); @@ -826,15 +882,29 @@ conf_report (void) for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) for (cb = LIST_FIRST(&conf_bindings[i]); cb; cb = LIST_NEXT(cb, link)) { if (!cb->is_default) { + /* Make sure the Section arugment is the same */ + if (current_arg && current_section && cb->arg) { + if (strcmp(cb->section, current_section) == 0 && + strcmp(cb->arg, current_arg) != 0) + diff_arg = 1; + } /* Dump this entry. */ - if (!current_section || strcmp(cb->section, current_section)) { - if (current_section) { + if (!current_section || strcmp(cb->section, current_section) + || diff_arg) { + if (current_section || diff_arg) { len = strlen (current_section) + 3; + if (current_arg) + len += strlen(current_arg) + 3; dnode->s = malloc(len); if (!dnode->s) goto mem_fail; - snprintf(dnode->s, len, "[%s]", current_section); + if (current_arg) + snprintf(dnode->s, len, "[%s \"%s\"]", + current_section, current_arg); + else + snprintf(dnode->s, len, "[%s]", current_section); + dnode->next = (struct dumper *)calloc(1, sizeof (struct dumper)); dnode = dnode->next; @@ -849,6 +919,8 @@ conf_report (void) goto mem_fail; } current_section = cb->section; + current_arg = cb->arg; + diff_arg = 0; } dnode->s = cb->tag; dnode->v = cb->value; @@ -862,10 +934,15 @@ conf_report (void) if (last) { len = strlen(last->section) + 3; + if (last->arg) + len += strlen(last->arg) + 3; dnode->s = malloc(len); if (!dnode->s) goto mem_fail; - snprintf(dnode->s, len, "[%s]", last->section); + if (last->arg) + snprintf(dnode->s, len, "[%s \"%s\"]", last->section, last->arg); + else + snprintf(dnode->s, len, "[%s]", last->section); } conf_report_dump(dumper); return;