]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/db-ctl-base.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / db-ctl-base.c
index ef35ee98c4e91b19416cfe2bc43f8ef182f30319..e95c77da2cf60a03e6024c89ae92d1b21ee8b525 100644 (file)
@@ -430,31 +430,39 @@ static char *
 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
@@ -690,7 +698,9 @@ check_mutable(const struct ovsdb_idl_row *row,
     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,
@@ -703,7 +713,8 @@ is_set_operator(enum relop op)
 {
     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
@@ -731,9 +742,12 @@ evaluate_relop(const struct ovsdb_datum *a, const struct ovsdb_datum *b,
     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();
@@ -919,8 +933,8 @@ cmd_get(struct ctl_context *ctx)
     }
 
     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) {
@@ -986,6 +1000,7 @@ cmd_get(struct ctl_context *ctx)
                         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 {
@@ -1206,27 +1221,35 @@ cmd_list(struct ctl_context *ctx)
 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;
 }
 
@@ -1279,7 +1302,7 @@ cmd_find(struct ctl_context *ctx)
         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);
@@ -1488,17 +1511,20 @@ cmd_add(struct ctl_context *ctx)
         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);
@@ -1579,10 +1605,12 @@ cmd_remove(struct ctl_context *ctx)
                                                      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;
             }
         }
@@ -1594,6 +1622,7 @@ cmd_remove(struct ctl_context *ctx)
                   "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);
@@ -1698,7 +1727,7 @@ cmd_create(struct ctl_context *ctx)
     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);
@@ -1706,7 +1735,7 @@ cmd_create(struct ctl_context *ctx)
         return;
     }
     if (id) {
-        struct ovsdb_symbol *symbol;
+        struct ovsdb_symbol *symbol = NULL;
 
         ctx->error = create_symbol(ctx->symtab, id, &symbol, NULL);
         if (ctx->error) {
@@ -1719,8 +1748,6 @@ cmd_create(struct ctl_context *ctx)
             symbol->strong_ref = true;
         }
         uuid = &symbol->uuid;
-    } else {
-        uuid = NULL;
     }
 
     row = ovsdb_idl_txn_insert(ctx->txn, table, uuid);
@@ -1785,11 +1812,15 @@ cmd_destroy(struct ctl_context *ctx)
     }
 
     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) {
@@ -1877,7 +1908,7 @@ cmd_wait_until(struct ctl_context *ctx)
 }
 
 /* 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)
 {
@@ -1885,6 +1916,7 @@ parse_command(int argc, char *argv[], struct shash *local_options,
     struct shash_node *node;
     int n_arg;
     int i;
+    char *error;
 
     shash_init(&command->options);
     shash_swap(local_options, &command->options);
@@ -1907,17 +1939,23 @@ parse_command(int argc, char *argv[], struct shash *local_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) {
@@ -1925,43 +1963,54 @@ parse_command(int argc, char *argv[], struct shash *local_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
@@ -2230,17 +2279,21 @@ ctl_add_cmd_options(struct option **options_p, size_t *n_options_p,
 }
 
 /* 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) {
@@ -2253,19 +2306,32 @@ ctl_parse_commands(int argc, char *argv[], struct shash *local_options,
                         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. */