]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/nfs/conffile.c
rpc.idmap: Hide global symbols from libidmap plugins
[nfs-utils.git] / support / nfs / conffile.c
index a8b803758f85c2f58d196bb2643874a2371ddb61..5015e945691a7c513700c093c0f37b76a2b7532b 100644 (file)
 #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;