get_column(const struct ovsdb_idl_table_class *table, const char *column_name,
const struct ovsdb_idl_column **columnp)
{
+ struct sset best_matches = SSET_INITIALIZER(&best_matches);
const struct ovsdb_idl_column *best_match = NULL;
unsigned int best_score = 0;
- size_t i;
- for (i = 0; i < table->n_columns; i++) {
+ for (size_t i = 0; i < table->n_columns; i++) {
const struct ovsdb_idl_column *column = &table->columns[i];
unsigned int score = score_partial_match(column->name, column_name);
- if (score > best_score) {
+ if (score && score >= best_score) {
+ if (score > best_score) {
+ sset_clear(&best_matches);
+ }
+ sset_add(&best_matches, column->name);
best_match = column;
best_score = score;
- } else if (score == best_score) {
- best_match = NULL;
}
}
- *columnp = best_match;
- if (best_match) {
- return NULL;
- } else if (best_score) {
- return xasprintf("%s contains more than one column whose name "
- "matches \"%s\"", table->name, column_name);
+ char *error = NULL;
+ *columnp = NULL;
+ if (!best_match) {
+ error = xasprintf("%s does not contain a column whose name matches "
+ "\"%s\"", table->name, column_name);
+ } else if (sset_count(&best_matches) == 1) {
+ *columnp = best_match;
} else {
- return xasprintf("%s does not contain a column whose name matches "
- "\"%s\"", table->name, column_name);
+ char *matches = sset_join(&best_matches, ", ", "");
+ error = xasprintf("%s contains more than one column "
+ "whose name matches \"%s\": %s",
+ table->name, column_name, matches);
+ free(matches);
}
+ sset_destroy(&best_matches);
+ return error;
}
static char * OVS_WARN_UNUSED_RESULT
RELOP(RELOP_SET_LT, "{<}") \
RELOP(RELOP_SET_GT, "{>}") \
RELOP(RELOP_SET_LE, "{<=}") \
- RELOP(RELOP_SET_GE, "{>=}")
+ RELOP(RELOP_SET_GE, "{>=}") \
+ RELOP(RELOP_SET_IN, "{in}") \
+ RELOP(RELOP_SET_NOT_IN, "{not-in}")
enum relop {
#define RELOP(ENUM, STRING) ENUM,
{
return (op == RELOP_SET_EQ || op == RELOP_SET_NE ||
op == RELOP_SET_LT || op == RELOP_SET_GT ||
- op == RELOP_SET_LE || op == RELOP_SET_GE);
+ op == RELOP_SET_LE || op == RELOP_SET_GE ||
+ op == RELOP_SET_IN || op == RELOP_SET_NOT_IN);
}
static bool
case RELOP_SET_GT:
return a->n > b->n && ovsdb_datum_includes_all(b, a, type);
case RELOP_SET_LE:
+ case RELOP_SET_IN:
return ovsdb_datum_includes_all(a, b, type);
case RELOP_SET_GE:
return ovsdb_datum_includes_all(b, a, type);
+ case RELOP_SET_NOT_IN:
+ return ovsdb_datum_excludes_all(a, b, type);
default:
OVS_NOT_REACHED();
}
if (id) {
- struct ovsdb_symbol *symbol;
- bool new;
+ struct ovsdb_symbol *symbol = NULL;
+ bool new = false;
ctx->error = create_symbol(ctx->symtab, id, &symbol, &new);
if (ctx->error) {
ctx, "no key \"%s\" in %s record \"%s\" column %s",
key_string, table->name, record_id, column->name);
free(key_string);
+ ovsdb_atom_destroy(&key, column->type.key.type);
return;
}
} else {
static char * OVS_WARN_UNUSED_RESULT
get_table(const char *table_name, const struct ovsdb_idl_table_class **tablep)
{
+ struct sset best_matches = SSET_INITIALIZER(&best_matches);
const struct ovsdb_idl_table_class *best_match = NULL;
unsigned int best_score = 0;
- char *error = NULL;
for (const struct ovsdb_idl_table_class *table = idl_classes;
table < &idl_classes[n_classes]; table++) {
unsigned int score = score_partial_match(table->name, table_name);
- if (score > best_score) {
+ if (score && score >= best_score) {
+ if (score > best_score) {
+ sset_clear(&best_matches);
+ }
+ sset_add(&best_matches, table->name);
best_match = table;
best_score = score;
- } else if (score == best_score) {
- best_match = NULL;
}
}
- if (best_match) {
+
+ char *error = NULL;
+ if (!best_match) {
+ error = xasprintf("unknown table \"%s\"", table_name);
+ } else if (sset_count(&best_matches) == 1) {
*tablep = best_match;
- } else if (best_score) {
- error = xasprintf("multiple table names match \"%s\"", table_name);
} else {
- error = xasprintf("unknown table \"%s\"", table_name);
+ char *matches = sset_join(&best_matches, ", ", "");
+ error = xasprintf("\"%s\" matches multiple table names: %s",
+ table_name, matches);
+ free(matches);
}
+ sset_destroy(&best_matches);
return error;
}
int i;
for (i = 2; i < ctx->argc; i++) {
- bool satisfied;
+ bool satisfied = false;
ctx->error = check_condition(table, row, ctx->argv[i],
ctx->symtab, &satisfied);
ctx->error = ovsdb_datum_from_string(&add, &add_type, ctx->argv[i],
ctx->symtab);
if (ctx->error) {
+ ovsdb_datum_destroy(&old, &column->type);
return;
}
ovsdb_datum_union(&old, &add, type, false);
ovsdb_datum_destroy(&add, type);
}
if (old.n > type->n_max) {
- ctl_fatal("\"add\" operation would put %u %s in column %s of "
+ ctl_error(ctx, "\"add\" operation would put %u %s in column %s of "
"table %s but the maximum number is %u",
old.n,
type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs",
column->name, table->name, type->n_max);
+ ovsdb_datum_destroy(&old, &column->type);
+ return;
}
ovsdb_idl_txn_verify(row, column);
ovsdb_idl_txn_write(row, column, &old);
ctx->argv[i],
ctx->symtab);
if (ctx->error) {
+ ovsdb_datum_destroy(&old, &column->type);
return;
}
} else {
ctx->error = error;
+ ovsdb_datum_destroy(&old, &column->type);
return;
}
}
"table %s but the minimum number is %u", old.n,
type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs",
column->name, table->name, type->n_min);
+ ovsdb_datum_destroy(&old, &column->type);
return;
}
ovsdb_idl_txn_verify(row, column);
const char *table_name = ctx->argv[1];
const struct ovsdb_idl_table_class *table;
const struct ovsdb_idl_row *row;
- const struct uuid *uuid;
+ const struct uuid *uuid = NULL;
int i;
ctx->error = get_table(table_name, &table);
return;
}
if (id) {
- struct ovsdb_symbol *symbol;
+ struct ovsdb_symbol *symbol = NULL;
ctx->error = create_symbol(ctx->symtab, id, &symbol, NULL);
if (ctx->error) {
symbol->strong_ref = true;
}
uuid = &symbol->uuid;
- } else {
- uuid = NULL;
}
row = ovsdb_idl_txn_insert(ctx->txn, table, uuid);
}
if (delete_all && ctx->argc > 2) {
- ctl_fatal("--all and records argument should not be specified together");
+ ctl_error(ctx, "--all and records argument should not be specified "
+ "together");
+ return;
}
if (delete_all && !must_exist) {
- ctl_fatal("--all and --if-exists should not be specified together");
+ ctl_error(ctx, "--all and --if-exists should not be specified "
+ "together");
+ return;
}
if (delete_all) {
}
/* Parses one command. */
-static void
+static char * OVS_WARN_UNUSED_RESULT
parse_command(int argc, char *argv[], struct shash *local_options,
struct ctl_command *command)
{
struct shash_node *node;
int n_arg;
int i;
+ char *error;
shash_init(&command->options);
shash_swap(local_options, &command->options);
}
if (shash_find(&command->options, key)) {
- ctl_fatal("'%s' option specified multiple times", argv[i]);
+ free(key);
+ free(value);
+ error = xasprintf("'%s' option specified multiple times", argv[i]);
+ goto error;
}
shash_add_nocopy(&command->options, key, value);
}
if (i == argc) {
- ctl_fatal("missing command name (use --help for help)");
+ error = xstrdup("missing command name (use --help for help)");
+ goto error;
}
p = shash_find_data(&all_commands, argv[i]);
if (!p) {
- ctl_fatal("unknown command '%s'; use --help for help", argv[i]);
+ error = xasprintf("unknown command '%s'; use --help for help",
+ argv[i]);
+ goto error;
}
SHASH_FOR_EACH (node, &command->options) {
int end = s ? s[strlen(node->name)] : EOF;
if (!strchr("=,? ", end)) {
- ctl_fatal("'%s' command has no '%s' option",
- argv[i], node->name);
+ error = xasprintf("'%s' command has no '%s' option",
+ argv[i], node->name);
+ goto error;
}
if (end != '?' && (end == '=') != (node->data != NULL)) {
if (end == '=') {
- ctl_fatal("missing argument to '%s' option on '%s' "
- "command", node->name, argv[i]);
+ error = xasprintf("missing argument to '%s' option on '%s' "
+ "command", node->name, argv[i]);
+ goto error;
} else {
- ctl_fatal("'%s' option on '%s' does not accept an "
- "argument", node->name, argv[i]);
+ error = xasprintf("'%s' option on '%s' does not accept an "
+ "argument", node->name, argv[i]);
+ goto error;
}
}
}
n_arg = argc - i - 1;
if (n_arg < p->min_args) {
- ctl_fatal("'%s' command requires at least %d arguments",
- p->name, p->min_args);
+ error = xasprintf("'%s' command requires at least %d arguments",
+ p->name, p->min_args);
+ goto error;
} else if (n_arg > p->max_args) {
int j;
for (j = i + 1; j < argc; j++) {
if (argv[j][0] == '-') {
- ctl_fatal("'%s' command takes at most %d arguments "
- "(note that options must precede command "
- "names and follow a \"--\" argument)",
- p->name, p->max_args);
+ error = xasprintf("'%s' command takes at most %d arguments "
+ "(note that options must precede command "
+ "names and follow a \"--\" argument)",
+ p->name, p->max_args);
+ goto error;
}
}
- ctl_fatal("'%s' command takes at most %d arguments",
- p->name, p->max_args);
+ error = xasprintf("'%s' command takes at most %d arguments",
+ p->name, p->max_args);
+ goto error;
}
command->syntax = p;
command->argc = n_arg + 1;
command->argv = &argv[i];
+ return NULL;
+
+error:
+ shash_destroy_free_data(&command->options);
+ return error;
}
static void
}
/* Parses command-line input for commands. */
-struct ctl_command *
+char *
ctl_parse_commands(int argc, char *argv[], struct shash *local_options,
- size_t *n_commandsp)
+ struct ctl_command **commandsp, size_t *n_commandsp)
{
struct ctl_command *commands;
size_t n_commands, allocated_commands;
int i, start;
+ char *error;
commands = NULL;
n_commands = allocated_commands = 0;
+ *commandsp = NULL;
+ *n_commandsp = 0;
+
for (start = i = 0; i <= argc; i++) {
if (i == argc || !strcmp(argv[i], "--")) {
if (i > start) {
shash_moved(&c->options);
}
}
- parse_command(i - start, &argv[start], local_options,
- &commands[n_commands++]);
+ error = parse_command(i - start, &argv[start], local_options,
+ &commands[n_commands]);
+ if (error) {
+ struct ctl_command *c;
+
+ for (c = commands; c < &commands[n_commands]; c++) {
+ shash_destroy_free_data(&c->options);
+ }
+ free(commands);
+
+ return error;
+ }
+
+ n_commands++;
} else if (!shash_is_empty(local_options)) {
- ctl_fatal("missing command name (use --help for help)");
+ return xstrdup("missing command name (use --help for help)");
}
start = i + 1;
}
}
if (!n_commands) {
- ctl_fatal("missing command name (use --help for help)");
+ return xstrdup("missing command name (use --help for help)");
}
+ *commandsp = commands;
*n_commandsp = n_commands;
- return commands;
+ return NULL;
}
/* Prints all registered commands. */