X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=utilities%2Fovs-vsctl.c;h=f4b2c25afbf3f7557a259d0c34d1f3569731a649;hb=90c4bd001ae4a0f6b091db2af6fc664b110aafea;hp=0eef55f0935b877a970d4e290055c7410ab4e292;hpb=93255bc565f74df887c0278f8e401d3febd7e61a;p=sliver-openvswitch.git diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index 0eef55f09..f4b2c25af 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -1648,6 +1648,14 @@ static const struct vsctl_table_class tables[] = { {NULL, NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}} }; +static void +die_if_error(char *error) +{ + if (error) { + ovs_fatal(0, "%s", error); + } +} + static int to_lower_and_underscores(unsigned c) { @@ -1659,11 +1667,14 @@ score_partial_match(const char *name, const char *s) { int score; + if (!strcmp(name, s)) { + return UINT_MAX; + } for (score = 0; ; score++, name++, s++) { if (to_lower_and_underscores(*name) != to_lower_and_underscores(*s)) { break; } else if (*name == '\0') { - return UINT_MAX; + return UINT_MAX - 1; } } return *s == '\0' ? score : 0; @@ -1791,8 +1802,9 @@ get_row(struct vsctl_context *ctx, return row; } -static const struct vsctl_column * -get_column(const struct vsctl_table_class *table, const char *column_name) +static char * +get_column(const struct vsctl_table_class *table, const char *column_name, + const struct vsctl_column **columnp) { const struct vsctl_column *column; const struct vsctl_column *best_match = NULL; @@ -1810,44 +1822,52 @@ get_column(const struct vsctl_table_class *table, const char *column_name) } } } + + *columnp = best_match; if (best_match) { - return best_match; + return NULL; } else if (best_score) { - ovs_fatal(0, "%s has more than one column whose name matches \"%s\"", - table->class->name, column_name); + return xasprintf("%s contains more than one column whose name " + "matches \"%s\"", table->class->name, column_name); } else { - ovs_fatal(0, "%s does not have a column \"%s\"", - table->class->name, column_name); - } -} - -static void -check_trailer(const char *s, const char *p) -{ - if (*p != '\0') { - ovs_fatal(0, "%s: trailing garbage in argument at offset %td", - s, p - s); + return xasprintf("%s does not contain a column whose name matches " + "\"%s\"", table->class->name, column_name); } } -static void +static char * WARN_UNUSED_RESULT parse_column_key_value(const char *arg, const struct vsctl_table_class *table, const struct vsctl_column **columnp, char **keyp, char **valuep) { const char *p = arg; + char *error; assert(columnp || keyp); + if (keyp) { + *keyp = NULL; + } + if (valuep) { + *valuep = NULL; + } /* Parse column name. */ if (columnp) { char *column_name; - p = ovsdb_token_parse(arg, &column_name); + error = ovsdb_token_parse(&arg, &column_name); + if (error) { + goto error; + } if (column_name[0] == '\0') { - ovs_fatal(0, "%s: missing column name", arg); + free(column_name); + error = xasprintf("%s: missing column name", arg); + goto error; + } + error = get_column(table, column_name, columnp); + if (error) { + goto error; } - *columnp = get_column(table, column_name); free(column_name); } @@ -1856,9 +1876,13 @@ parse_column_key_value(const char *arg, const struct vsctl_table_class *table, if (columnp) { p++; } else if (!keyp) { - ovs_fatal(0, "%s: key not accepted here", arg); + error = xasprintf("%s: key not accepted here", arg); + goto error; + } + error = ovsdb_token_parse(&p, keyp); + if (error) { + goto error; } - p = ovsdb_token_parse(p, keyp); } else if (keyp) { *keyp = NULL; } @@ -1866,16 +1890,35 @@ parse_column_key_value(const char *arg, const struct vsctl_table_class *table, /* Parse value string. */ if (*p == '=') { if (!valuep) { - ovs_fatal(0, "%s: value not accepted here", arg); + error = xasprintf("%s: value not accepted here", arg); + goto error; } *valuep = xstrdup(p + 1); - return; } else { if (valuep) { *valuep = NULL; } - check_trailer(arg, p); + if (*p != '\0') { + error = xasprintf("%s: trailing garbage in argument at offset %td", + arg, p - arg); + goto error; + } + } + return NULL; + +error: + if (columnp) { + *columnp = NULL; } + if (keyp) { + free(*keyp); + *keyp = NULL; + } + if (valuep) { + free(*valuep); + *valuep = NULL; + } + return error; } static void @@ -1895,8 +1938,8 @@ cmd_get(struct vsctl_context *ctx) struct ovsdb_datum datum; char *key_string; - parse_column_key_value(ctx->argv[i], table, - &column, &key_string, NULL); + die_if_error(parse_column_key_value(ctx->argv[i], table, + &column, &key_string, NULL)); ovsdb_idl_txn_read(row, column->idl, &datum); if (key_string) { @@ -1908,8 +1951,9 @@ cmd_get(struct vsctl_context *ctx) column->idl->name); } - ovsdb_atom_from_string(&key, column->idl->type.key_type, - key_string); + die_if_error(ovsdb_atom_from_string(&key, + column->idl->type.key_type, + key_string)); idx = ovsdb_datum_find_key(&datum, &key, column->idl->type.key_type); @@ -1934,12 +1978,13 @@ cmd_get(struct vsctl_context *ctx) } static void -list_record(const struct vsctl_table_class *table, const struct ovsdb_idl_row *row, - struct ds *out) +list_record(const struct vsctl_table_class *table, + const struct ovsdb_idl_row *row, struct ds *out) { const struct vsctl_column *column; - ds_put_format(out, "%-20s: "UUID_FMT"\n", "_uuid", UUID_ARGS(&row->uuid)); + ds_put_format(out, "%-20s (RO): "UUID_FMT"\n", "_uuid", + UUID_ARGS(&row->uuid)); for (column = table->columns; column->idl; column++) { struct ovsdb_datum datum; @@ -2088,9 +2133,11 @@ cmd_set(struct vsctl_context *ctx) for (i = 3; i < ctx->argc; i++) { const struct vsctl_column *column; char *key_string, *value_string; + char *error; - parse_column_key_value(ctx->argv[i], table, - &column, &key_string, &value_string); + error = parse_column_key_value(ctx->argv[i], table, + &column, &key_string, &value_string); + die_if_error(error); if (column->flags & VSCF_READONLY) { ovs_fatal(0, "%s: cannot modify read-only column %s in table %s", ctx->argv[i], column->idl->name, table_name); @@ -2108,10 +2155,12 @@ cmd_set(struct vsctl_context *ctx) column->idl->name); } - ovsdb_atom_from_string(&key, column->idl->type.key_type, - key_string); - ovsdb_atom_from_string(&value, column->idl->type.value_type, - value_string); + die_if_error(ovsdb_atom_from_string(&key, + column->idl->type.key_type, + key_string)); + die_if_error(ovsdb_atom_from_string(&value, + column->idl->type.value_type, + value_string)); ovsdb_datum_init_empty(&new); ovsdb_datum_add_unsafe(&new, &key, &value, &column->idl->type); @@ -2124,7 +2173,8 @@ cmd_set(struct vsctl_context *ctx) } else { struct ovsdb_datum datum; - ovsdb_datum_from_string(&datum, &column->idl->type, value_string); + die_if_error(ovsdb_datum_from_string(&datum, &column->idl->type, + value_string)); check_constraint(&datum, &column->idl->type, column->constraint); ovsdb_idl_txn_write(row, column->idl, &datum); } @@ -2149,7 +2199,7 @@ cmd_add(struct vsctl_context *ctx) table = get_table(table_name); row = get_row(ctx, table, record_id); - column = get_column(table, column_name); + die_if_error(get_column(table, column_name, &column)); type = &column->idl->type; ovsdb_idl_txn_read(row, column->idl, &old); for (i = 4; i < ctx->argc; i++) { @@ -2164,7 +2214,7 @@ cmd_add(struct vsctl_context *ctx) add_type = *type; add_type.n_min = 1; add_type.n_max = UINT_MAX; - ovsdb_datum_from_string(&add, &add_type, ctx->argv[i]); + die_if_error(ovsdb_datum_from_string(&add, &add_type, ctx->argv[i])); ovsdb_datum_union(&old, &add, type, false); ovsdb_datum_destroy(&add, type); } @@ -2177,6 +2227,89 @@ cmd_add(struct vsctl_context *ctx) } ovsdb_idl_txn_write(row, column->idl, &old); } + +static void +cmd_remove(struct vsctl_context *ctx) +{ + const char *table_name = ctx->argv[1]; + const char *record_id = ctx->argv[2]; + const char *column_name = ctx->argv[3]; + const struct vsctl_table_class *table; + const struct vsctl_column *column; + const struct ovsdb_idl_row *row; + const struct ovsdb_type *type; + struct ovsdb_datum old; + int i; + + table = get_table(table_name); + row = get_row(ctx, table, record_id); + die_if_error(get_column(table, column_name, &column)); + type = &column->idl->type; + ovsdb_idl_txn_read(row, column->idl, &old); + for (i = 4; i < ctx->argc; i++) { + struct ovsdb_type rm_type; + struct ovsdb_datum rm; + char *error; + + if (column->flags & VSCF_READONLY) { + ovs_fatal(0, "%s: cannot modify read-only column %s in table %s", + ctx->argv[i], column->idl->name, table_name); + } + + rm_type = *type; + rm_type.n_min = 1; + rm_type.n_max = UINT_MAX; + error = ovsdb_datum_from_string(&rm, &rm_type, ctx->argv[i]); + if (error && ovsdb_type_is_map(&rm_type)) { + free(error); + rm_type.value_type = OVSDB_TYPE_VOID; + die_if_error(ovsdb_datum_from_string(&rm, &rm_type, ctx->argv[i])); + } + ovsdb_datum_subtract(&old, type, &rm, &rm_type); + ovsdb_datum_destroy(&rm, &rm_type); + } + if (old.n < type->n_min) { + ovs_fatal(0, "\"remove\" operation would put %u %s in column %s of " + "table %s but at least %u are required", + old.n, + type->value_type == OVSDB_TYPE_VOID ? "values" : "pairs", + column->idl->name, table_name, type->n_min); + } + ovsdb_idl_txn_write(row, column->idl, &old); +} + +static void +cmd_clear(struct vsctl_context *ctx) +{ + const char *table_name = ctx->argv[1]; + const char *record_id = ctx->argv[2]; + const struct vsctl_table_class *table; + const struct ovsdb_idl_row *row; + int i; + + table = get_table(table_name); + row = get_row(ctx, table, record_id); + for (i = 3; i < ctx->argc; i++) { + const struct vsctl_column *column; + const struct ovsdb_type *type; + struct ovsdb_datum datum; + + die_if_error(get_column(table, ctx->argv[i], &column)); + + type = &column->idl->type; + if (column->flags & VSCF_READONLY) { + ovs_fatal(0, "%s: cannot modify read-only column %s in table %s", + ctx->argv[i], column->idl->name, table_name); + } else if (type->n_min > 0) { + ovs_fatal(0, "\"clear\" operation cannot be applied to column %s " + "of table %s, which is not allowed to be empty", + column->idl->name, table_name); + } + + ovsdb_datum_init_empty(&datum); + ovsdb_idl_txn_write(row, column->idl, &datum); + } +} typedef void vsctl_handler_func(struct vsctl_context *); @@ -2387,11 +2520,8 @@ get_vsctl_handler(int argc, char *argv[], struct vsctl_context *ctx) {"list", 1, INT_MAX, cmd_list, ""}, {"set", 3, INT_MAX, cmd_set, ""}, {"add", 4, INT_MAX, cmd_add, ""}, -#if 0 - /* XXX Not yet implemented. */ {"remove", 4, INT_MAX, cmd_remove, ""}, {"clear", 3, INT_MAX, cmd_clear, ""}, -#endif }; const struct vsctl_command *p;