summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralex <alex@builder.localdomain>2007-12-11 15:12:36 -0800
committeralex <alex@builder.localdomain>2007-12-11 15:12:36 -0800
commitfb9450551d5757a45806a062d7457a761e6dd295 (patch)
treecda8e28bdf2c1bc23d98de6de9437b1c90c5f654
parent1d78b0c336c8d3ae62f65983098584a6e2e613ce (diff)
downloadvyatta-cfg-fb9450551d5757a45806a062d7457a761e6dd295.tar.gz
vyatta-cfg-fb9450551d5757a45806a062d7457a761e6dd295.zip
Bug #2509
Multivalue nodes are diffed with previous value for validation before commit.
-rw-r--r--src/cli_new.c95
-rw-r--r--src/cli_objects.c2
-rw-r--r--src/cli_val.h1
-rw-r--r--src/commit.c24
-rw-r--r--templates/interfaces/ethernet/node.tag/address/node.def2
5 files changed, 116 insertions, 8 deletions
diff --git a/src/cli_new.c b/src/cli_new.c
index 0f5abd9..c51be7f 100644
--- a/src/cli_new.c
+++ b/src/cli_new.c
@@ -56,8 +56,13 @@ static int cond_format_lens[DOMAIN_TYPE] =
6 /* MACADDR_TYPE */
};
+struct __slist_t;
+
+typedef struct __slist_t {
+ struct __slist_t *next;
+} slist_t;
+
static int cli_val_len;
-static char *cli_val_alloc;
static char *cli_val_ptr;
static char *exe_string;
@@ -82,6 +87,8 @@ static void free_reuse_list(void);
void free_path(vtw_path *path);
static void free_string(char *str);
static vtw_node * get_node(void);
+void subtract_values(char **lhs, const char *rhs);
+
static void scan_ipv6(char *val, unsigned int *parts);
@@ -1518,7 +1525,6 @@ int get_value(char **valpp, vtw_path *pathp)
readcnt = fread(valp, 1, statbuf.st_size, in);
if (readcnt != statbuf.st_size) {
my_free(valp);
- cli_val_alloc = 0;
err = "Error reading value file in [%s]\n";
goto bad_path;
}
@@ -1784,6 +1790,91 @@ boolean validate_value(vtw_def *def, char *cp)
return ret;
}
+typedef struct __value_list {
+ slist_t link;
+ const char *value;
+} value_list;
+
+static void delete_list(slist_t *head)
+{
+ while (head != NULL) {
+ slist_t *elem = head;
+ head = head->next;
+ my_free(elem);
+ }
+}
+
+void subtract_values(char **lhs, const char *rhs)
+{
+ size_t length = 0;
+ const char *line = NULL;
+ char *rhs_copy = NULL, *res = NULL;
+ slist_t *head = NULL, *ptr = NULL;
+ slist_t *new_head = NULL, *new_ptr = NULL;
+
+ if (lhs == NULL || *lhs == NULL || **lhs == '\0' || rhs == NULL || *rhs == '\0')
+ return;
+
+ rhs_copy = my_malloc(strlen(rhs), "subtract_values rhs_copy");
+ strcpy(rhs_copy, rhs);
+
+ head = ptr = my_malloc(sizeof(slist_t), "subtract_values list1");
+ memset(head, 0, sizeof(slist_t));
+
+ line = strtok(rhs_copy, "\n\r");
+ while (line != NULL && *line != '\0') {
+ value_list *elem = NULL;
+
+ elem = (value_list *) my_malloc(sizeof(value_list), "subtract_values elem1");
+ memset(elem, 0, sizeof(value_list));
+ elem->value = line;
+ ptr->next = (slist_t *) elem;
+ ptr = ptr->next;
+ line = strtok(NULL, "\n\r");
+ }
+
+ new_head = new_ptr = my_malloc(sizeof(slist_t), "subtract_values list2");
+ memset(new_head, 0, sizeof(slist_t));
+
+ line = strtok(*lhs, "\n\r");
+ while (line != NULL && *line != '\0') {
+ value_list *elem = NULL;
+
+ ptr = head;
+ while (ptr->next != NULL) {
+ elem = (value_list *) ptr->next;
+ if (strncmp(line, elem->value, strlen(line)) == 0)
+ break;
+ ptr = ptr->next;
+ }
+ if (ptr->next == NULL) {
+ elem = (value_list *) my_malloc(sizeof(value_list), "subtract_values elem2");
+ memset(elem, 0, sizeof(value_list));
+ elem->value = line;
+ new_ptr->next = elem;
+ new_ptr = new_ptr->next;
+ length += strlen(line) + 1;
+ }
+ line = strtok(NULL, "\n\r");
+ }
+
+ new_ptr = new_head->next;
+ res = (char *) my_malloc(length + 1, "subtract_values result");
+ *res = '\0';
+ while (new_ptr != NULL) {
+ strcat(res, ((value_list *) new_ptr)->value);
+ strcat(res, "\n");
+ new_ptr = new_ptr->next;
+ }
+
+ delete_list(head);
+ delete_list(new_head);
+ if (rhs_copy != NULL)
+ my_free(rhs_copy);
+ my_free(*lhs);
+
+ *lhs = res;
+}
int cli_val_read(char *buf, int max_size)
{
diff --git a/src/cli_objects.c b/src/cli_objects.c
index 9bb36f0..8f0f6fe 100644
--- a/src/cli_objects.c
+++ b/src/cli_objects.c
@@ -334,7 +334,7 @@ void init_paths(boolean for_commit)
init_path(&m_path, startp);
switch_path(get_f_seg_c_ptr());
m_path.print_offset = max_len;
- }else
+ } else
init_path(&m_path, mdirp);
init_path(&t_path, tdirp);
diff --git a/src/cli_val.h b/src/cli_val.h
index 7383263..edbda41 100644
--- a/src/cli_val.h
+++ b/src/cli_val.h
@@ -171,6 +171,7 @@ extern void dump_tree(vtw_node *node, int lev);
extern void dump_def(vtw_def *defp);
extern boolean val_cmp(valstruct *left, valstruct *right, vtw_cond_e cond);
extern void out_of_memory(void);
+extern void subtract_values(char **lhs, const char *rhs);
extern boolean validate_value(vtw_def *def,
char *value);
extern void internal_error(int line, char *file);
diff --git a/src/commit.c b/src/commit.c
index 4820094..2eedf6f 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -91,7 +91,7 @@ static boolean validate_dir_for_commit()
def_present = TRUE;
memset(&def, 0, sizeof(def));
#ifdef DEBUG1
- printf("Parsing definition\n");
+ printf("Parsing definition %s\n", t_path.path);
#endif
if ((status = parse_def(&def, t_path.path,
@@ -102,7 +102,7 @@ static boolean validate_dir_for_commit()
}
#ifdef DEBUG1
else
- printf("No definition\n");
+ printf("No definition %s\n", t_path.path);
#endif
pop_path(&t_path); /* for PUSH 1 */
@@ -156,11 +156,27 @@ static boolean validate_dir_for_commit()
/* read it */
cp = NULL;
status = get_value(&cp, &m_path);
- if (status == VTWERR_OK){
+ if (status == VTWERR_OK) {
#ifdef DEBUG1
printf("Validating value |%s|\n"
"for path %s\n", cp, m_path.path);
#endif
+
+ // multivalue has to be diff-ed with the pre-existing value.
+ // only the difference should be ran through the validation.
+ // Bug #2509
+ if (def.multi) {
+ char *old_value = NULL;
+ switch_path(APATH); // temporarily switching to the active config path
+ status = get_value(&old_value, &m_path);
+ if (status == VTWERR_OK) {
+ subtract_values(&cp, old_value);
+ }
+ switch_path(CPATH);
+ if (old_value)
+ my_free(old_value);
+ }
+
status = validate_value(&def, cp);
ret = ret && status;
}
@@ -232,7 +248,7 @@ static boolean validate_dir_for_commit()
}
if (def_present && def.tag)
- pop_path(&t_path); /* for PUSH 3a */
+ pop_path(&t_path); /* for PUSH 2a */
if (def_present)
free_def(&def);
#ifdef DEBUG
diff --git a/templates/interfaces/ethernet/node.tag/address/node.def b/templates/interfaces/ethernet/node.tag/address/node.def
index 9447c99..6cef105 100644
--- a/templates/interfaces/ethernet/node.tag/address/node.def
+++ b/templates/interfaces/ethernet/node.tag/address/node.def
@@ -2,5 +2,5 @@ multi:
type: txt
help: "Set IPv4 address and prefix for this interface"
syntax: exec "/opt/vyatta/sbin/vyatta-interfaces.pl --valid-addr $(@) --dev $(../@)"
-create: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-update $(@) --dev $(../@)"; "Error setting address $(@) on dev $(../@)"
+update: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-update $(@) --dev $(../@)"; "Error setting address $(@) on dev $(../@)"
delete: "sudo /opt/vyatta/sbin/vyatta-interfaces.pl --eth-addr-delete $(@) --dev $(../@)"; "Error deleting address $(@) on dev $(../@)"