ofpbuf: Fix trivial spelling typo.
[cascardo/ovs.git] / utilities / ovs-vsctl.c
index b114a5a..eeb711f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,7 +31,6 @@
 
 #include "command-line.h"
 #include "compiler.h"
-#include "dirs.h"
 #include "dynamic-string.h"
 #include "fatal-signal.h"
 #include "hash.h"
@@ -85,10 +84,15 @@ static bool retry;
 static struct table_style table_style = TABLE_STYLE_DEFAULT;
 
 static void vsctl_cmd_init(void);
-static char *default_db(void);
+
+/* The IDL we're using and the current transaction, if any.
+ * This is for use by vsctl_exit() only, to allow it to clean up.
+ * Other code should use its context arguments. */
+static struct ovsdb_idl *the_idl;
+static struct ovsdb_idl_txn *the_idl_txn;
+OVS_NO_RETURN static void vsctl_exit(int status);
+
 OVS_NO_RETURN static void usage(void);
-OVS_NO_RETURN static void print_vsctl_commands(void);
-OVS_NO_RETURN static void print_vsctl_options(const struct option *options);
 static void parse_options(int argc, char *argv[], struct shash *local_options);
 static void run_prerequisites(struct ctl_command[], size_t n_commands,
                               struct ovsdb_idl *);
@@ -126,7 +130,6 @@ static size_t allocated_neoteric_ifaces;
 int
 main(int argc, char *argv[])
 {
-    extern struct vlog_module VLM_reconnect;
     struct ovsdb_idl *idl;
     struct ctl_command *commands;
     struct shash local_options;
@@ -137,7 +140,7 @@ main(int argc, char *argv[])
     set_program_name(argv[0]);
     fatal_ignore_sigpipe();
     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
-    vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
+    vlog_set_levels_from_string_assert("reconnect:warn");
     ovsrec_init();
 
     vsctl_cmd_init();
@@ -188,30 +191,6 @@ main(int argc, char *argv[])
     }
 }
 
-static struct option *
-find_option(const char *name, struct option *options, size_t n_options)
-{
-    size_t i;
-
-    for (i = 0; i < n_options; i++) {
-        if (!strcmp(options[i].name, name)) {
-            return &options[i];
-        }
-    }
-    return NULL;
-}
-
-static struct option *
-add_option(struct option **optionsp, size_t *n_optionsp,
-           size_t *allocated_optionsp)
-{
-    if (*n_optionsp >= *allocated_optionsp) {
-        *optionsp = x2nrealloc(*optionsp, allocated_optionsp,
-                               sizeof **optionsp);
-    }
-    return &(*optionsp)[(*n_optionsp)++];
-}
-
 static void
 parse_options(int argc, char *argv[], struct shash *local_options)
 {
@@ -221,6 +200,7 @@ parse_options(int argc, char *argv[], struct shash *local_options)
         OPT_NO_SYSLOG,
         OPT_NO_WAIT,
         OPT_DRY_RUN,
+        OPT_BOOTSTRAP_CA_CERT,
         OPT_PEER_CA_CERT,
         OPT_LOCAL,
         OPT_RETRY,
@@ -244,14 +224,14 @@ parse_options(int argc, char *argv[], struct shash *local_options)
         VLOG_LONG_OPTIONS,
         TABLE_LONG_OPTIONS,
         STREAM_SSL_LONG_OPTIONS,
+        {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
         {NULL, 0, NULL, 0},
     };
     const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
     char *tmp, *short_options;
 
-    const struct shash_node *node;
-    struct option *options, *o;
+    struct option *options;
     size_t allocated_options;
     size_t n_options;
     size_t i;
@@ -267,50 +247,7 @@ parse_options(int argc, char *argv[], struct shash *local_options)
     options = xmemdup(global_long_options, sizeof global_long_options);
     allocated_options = ARRAY_SIZE(global_long_options);
     n_options = n_global_long_options;
-    SHASH_FOR_EACH (node, ctl_get_all_commands()) {
-        const struct ctl_command_syntax *p = node->data;
-
-        if (p->options[0]) {
-            char *save_ptr = NULL;
-            char *name;
-            char *s;
-
-            s = xstrdup(p->options);
-            for (name = strtok_r(s, ",", &save_ptr); name != NULL;
-                 name = strtok_r(NULL, ",", &save_ptr)) {
-                char *equals;
-                int has_arg;
-
-                ovs_assert(name[0] == '-' && name[1] == '-' && name[2]);
-                name += 2;
-
-                equals = strchr(name, '=');
-                if (equals) {
-                    has_arg = required_argument;
-                    *equals = '\0';
-                } else {
-                    has_arg = no_argument;
-                }
-
-                o = find_option(name, options, n_options);
-                if (o) {
-                    ovs_assert(o - options >= n_global_long_options);
-                    ovs_assert(o->has_arg == has_arg);
-                } else {
-                    o = add_option(&options, &n_options, &allocated_options);
-                    o->name = xstrdup(name);
-                    o->has_arg = has_arg;
-                    o->flag = NULL;
-                    o->val = OPT_LOCAL;
-                }
-            }
-
-            free(s);
-        }
-    }
-    o = add_option(&options, &n_options, &allocated_options);
-    memset(o, 0, sizeof *o);
-
+    ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
     table_style.format = TF_LIST;
 
     for (;;) {
@@ -332,7 +269,7 @@ parse_options(int argc, char *argv[], struct shash *local_options)
             break;
 
         case OPT_NO_SYSLOG:
-            vlog_set_levels(&VLM_vsctl, VLF_SYSLOG, VLL_WARN);
+            vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
             break;
 
         case OPT_NO_WAIT:
@@ -357,10 +294,10 @@ parse_options(int argc, char *argv[], struct shash *local_options)
             usage();
 
         case OPT_COMMANDS:
-            print_vsctl_commands();
+            ctl_print_commands();
 
         case OPT_OPTIONS:
-            print_vsctl_options(global_long_options);
+            ctl_print_options(global_long_options);
 
         case 'V':
             ovs_print_version(0, 0);
@@ -388,6 +325,10 @@ parse_options(int argc, char *argv[], struct shash *local_options)
             stream_ssl_set_peer_ca_cert_file(optarg);
             break;
 
+        case OPT_BOOTSTRAP_CA_CERT:
+            stream_ssl_set_ca_cert_file(optarg, true);
+            break;
+
         case '?':
             exit(EXIT_FAILURE);
 
@@ -398,7 +339,7 @@ parse_options(int argc, char *argv[], struct shash *local_options)
     free(short_options);
 
     if (!db) {
-        db = default_db();
+        db = ctl_default_db();
     }
 
     for (i = n_global_long_options; options[i].name; i++) {
@@ -479,7 +420,7 @@ Options:\n\
   -t, --timeout=SECS          wait at most SECS seconds for ovs-vswitchd\n\
   --dry-run                   do not commit changes to database\n\
   --oneline                   print exactly one line of output per command\n",
-           program_name, program_name, ctl_get_db_cmd_usage(), default_db());
+           program_name, program_name, ctl_get_db_cmd_usage(), ctl_default_db());
     vlog_usage();
     printf("\
   --no-syslog             equivalent to --verbose=vsctl:syslog:warn\n");
@@ -491,142 +432,6 @@ Other options:\n\
     exit(EXIT_SUCCESS);
 }
 
-/* Converts the command arguments into format that can be parsed by
- * bash completion script.
- *
- * Therein, arguments will be attached with following prefixes:
- *
- *    !argument :: The argument is required
- *    ?argument :: The argument is optional
- *    *argument :: The argument may appear any number (0 or more) times
- *    +argument :: The argument may appear one or more times
- *
- */
-static void
-print_command_arguments(const struct ctl_command_syntax *command)
-{
-    /*
-     * The argument string is parsed in reverse.  We use a stack 'oew_stack' to
-     * keep track of nested optionals.  Whenever a ']' is encountered, we push
-     * a bit to 'oew_stack'.  The bit is set to 1 if the ']' is not nested.
-     * Subsequently, we pop an entry everytime '[' is met.
-     *
-     * We use 'whole_word_is_optional' value to decide whether or not a ! or +
-     * should be added on encountering a space: if the optional surrounds the
-     * whole word then it shouldn't be, but if it is only a part of the word
-     * (i.e. [key=]value), it should be.
-     */
-    uint32_t oew_stack = 0;
-
-    const char *arguments = command->arguments;
-    int length = strlen(arguments);
-    if (!length) {
-        return;
-    }
-
-    /* Output buffer, written backward from end. */
-    char *output = xmalloc(2 * length);
-    char *outp = output + 2 * length;
-    *--outp = '\0';
-
-    bool in_repeated = false;
-    bool whole_word_is_optional = false;
-
-    for (const char *inp = arguments + length; inp > arguments; ) {
-        switch (*--inp) {
-        case ']':
-            oew_stack <<= 1;
-            if (inp[1] == '\0' || inp[1] == ' ' || inp[1] == '.') {
-                oew_stack |= 1;
-            }
-            break;
-        case '[':
-            /* Checks if the whole word is optional, and sets the
-             * 'whole_word_is_optional' accordingly. */
-            if ((inp == arguments || inp[-1] == ' ') && oew_stack & 1) {
-                *--outp = in_repeated ? '*' : '?';
-                whole_word_is_optional = true;
-            } else {
-                *--outp = '?';
-                whole_word_is_optional = false;
-            }
-            oew_stack >>= 1;
-            break;
-        case ' ':
-            if (!whole_word_is_optional) {
-                *--outp = in_repeated ? '+' : '!';
-            }
-            *--outp = ' ';
-            in_repeated = false;
-            whole_word_is_optional = false;
-            break;
-        case '.':
-            in_repeated = true;
-            break;
-        default:
-            *--outp = *inp;
-            break;
-        }
-    }
-    if (arguments[0] != '[' && outp != output + 2 * length - 1) {
-        *--outp = in_repeated ? '+' : '!';
-    }
-    printf("%s", outp);
-    free(output);
-}
-
-static void
-print_vsctl_commands(void)
-{
-    const struct shash_node *node;
-
-    SHASH_FOR_EACH (node, ctl_get_all_commands()) {
-        const struct ctl_command_syntax *p = node->data;
-        char *options = xstrdup(p->options);
-        char *options_begin = options;
-        char *item;
-
-        for (item = strsep(&options, ","); item != NULL;
-             item = strsep(&options, ",")) {
-            if (item[0] != '\0') {
-                printf("[%s] ", item);
-            }
-        }
-        printf(",%s,", p->name);
-        print_command_arguments(p);
-        printf("\n");
-
-        free(options_begin);
-    }
-
-    exit(EXIT_SUCCESS);
-}
-
-static void
-print_vsctl_options(const struct option *options)
-{
-    for (; options->name; options++) {
-        const struct option *o = options;
-
-        printf("--%s%s\n", o->name, o->has_arg ? "=ARG" : "");
-        if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) {
-            printf("-%c%s\n", o->val, o->has_arg ? " ARG" : "");
-        }
-    }
-
-    exit(EXIT_SUCCESS);
-}
-
-static char *
-default_db(void)
-{
-    static char *def;
-    if (!def) {
-        def = xasprintf("unix:%s/db.sock", ovs_rundir());
-    }
-    return def;
-}
-
 \f
 /* ovs-vsctl specific context.  Inherits the 'struct ctl_context' as base. */
 struct vsctl_context {
@@ -677,7 +482,7 @@ struct vsctl_iface {
     struct vsctl_port *port;
 };
 
-/* Casts 'base' into 'strcut vsctl_context'. */
+/* Casts 'base' into 'struct vsctl_context'. */
 static struct vsctl_context *
 vsctl_context_cast(struct ctl_context *base)
 {
@@ -948,9 +753,6 @@ vsctl_context_populate_cache(struct ctl_context *ctx)
             continue;
         }
         br = add_bridge_to_cache(vsctl_ctx, br_cfg, br_cfg->name, NULL, 0);
-        if (!br) {
-            continue;
-        }
 
         for (j = 0; j < br_cfg->n_ports; j++) {
             struct ovsrec_port *port_cfg = br_cfg->ports[j];
@@ -1178,185 +980,57 @@ cmd_init(struct ctl_context *ctx OVS_UNUSED)
 {
 }
 
-struct cmd_show_table {
-    const struct ovsdb_idl_table_class *table;
-    const struct ovsdb_idl_column *name_column;
-    const struct ovsdb_idl_column *columns[3];
-    bool recurse;
-};
-
 static struct cmd_show_table cmd_show_tables[] = {
     {&ovsrec_table_open_vswitch,
      NULL,
      {&ovsrec_open_vswitch_col_manager_options,
       &ovsrec_open_vswitch_col_bridges,
       &ovsrec_open_vswitch_col_ovs_version},
-     false},
+     {NULL, NULL, NULL}
+    },
 
     {&ovsrec_table_bridge,
      &ovsrec_bridge_col_name,
      {&ovsrec_bridge_col_controller,
       &ovsrec_bridge_col_fail_mode,
       &ovsrec_bridge_col_ports},
-     false},
+     {NULL, NULL, NULL}
+    },
 
     {&ovsrec_table_port,
      &ovsrec_port_col_name,
      {&ovsrec_port_col_tag,
       &ovsrec_port_col_trunks,
       &ovsrec_port_col_interfaces},
-     false},
+     {NULL, NULL, NULL}
+    },
 
     {&ovsrec_table_interface,
      &ovsrec_interface_col_name,
      {&ovsrec_interface_col_type,
       &ovsrec_interface_col_options,
       &ovsrec_interface_col_error},
-     false},
+     {NULL, NULL, NULL}
+    },
 
     {&ovsrec_table_controller,
      &ovsrec_controller_col_target,
      {&ovsrec_controller_col_is_connected,
       NULL,
       NULL},
-     false},
+     {NULL, NULL, NULL}
+    },
 
     {&ovsrec_table_manager,
      &ovsrec_manager_col_target,
      {&ovsrec_manager_col_is_connected,
       NULL,
       NULL},
-     false},
-};
-
-static void
-pre_cmd_show(struct ctl_context *ctx)
-{
-    struct cmd_show_table *show;
-
-    for (show = cmd_show_tables;
-         show < &cmd_show_tables[ARRAY_SIZE(cmd_show_tables)];
-         show++) {
-        size_t i;
-
-        ovsdb_idl_add_table(ctx->idl, show->table);
-        if (show->name_column) {
-            ovsdb_idl_add_column(ctx->idl, show->name_column);
-        }
-        for (i = 0; i < ARRAY_SIZE(show->columns); i++) {
-            const struct ovsdb_idl_column *column = show->columns[i];
-            if (column) {
-                ovsdb_idl_add_column(ctx->idl, column);
-            }
-        }
-    }
-}
-
-static struct cmd_show_table *
-cmd_show_find_table_by_row(const struct ovsdb_idl_row *row)
-{
-    struct cmd_show_table *show;
-
-    for (show = cmd_show_tables;
-         show < &cmd_show_tables[ARRAY_SIZE(cmd_show_tables)];
-         show++) {
-        if (show->table == row->table->class) {
-            return show;
-        }
-    }
-    return NULL;
-}
-
-static struct cmd_show_table *
-cmd_show_find_table_by_name(const char *name)
-{
-    struct cmd_show_table *show;
-
-    for (show = cmd_show_tables;
-         show < &cmd_show_tables[ARRAY_SIZE(cmd_show_tables)];
-         show++) {
-        if (!strcmp(show->table->name, name)) {
-            return show;
-        }
-    }
-    return NULL;
-}
-
-static void
-cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row,
-             int level)
-{
-    struct cmd_show_table *show = cmd_show_find_table_by_row(row);
-    size_t i;
-
-    ds_put_char_multiple(&ctx->output, ' ', level * 4);
-    if (show && show->name_column) {
-        const struct ovsdb_datum *datum;
-
-        ds_put_format(&ctx->output, "%s ", show->table->name);
-        datum = ovsdb_idl_read(row, show->name_column);
-        ovsdb_datum_to_string(datum, &show->name_column->type, &ctx->output);
-    } else {
-        ds_put_format(&ctx->output, UUID_FMT, UUID_ARGS(&row->uuid));
-    }
-    ds_put_char(&ctx->output, '\n');
-
-    if (!show || show->recurse) {
-        return;
-    }
-
-    show->recurse = true;
-    for (i = 0; i < ARRAY_SIZE(show->columns); i++) {
-        const struct ovsdb_idl_column *column = show->columns[i];
-        const struct ovsdb_datum *datum;
-
-        if (!column) {
-            break;
-        }
+     {NULL, NULL, NULL}
+    },
 
-        datum = ovsdb_idl_read(row, column);
-        if (column->type.key.type == OVSDB_TYPE_UUID &&
-            column->type.key.u.uuid.refTableName) {
-            struct cmd_show_table *ref_show;
-            size_t j;
-
-            ref_show = cmd_show_find_table_by_name(
-                column->type.key.u.uuid.refTableName);
-            if (ref_show) {
-                for (j = 0; j < datum->n; j++) {
-                    const struct ovsdb_idl_row *ref_row;
-
-                    ref_row = ovsdb_idl_get_row_for_uuid(ctx->idl,
-                                                         ref_show->table,
-                                                         &datum->keys[j].uuid);
-                    if (ref_row) {
-                        cmd_show_row(ctx, ref_row, level + 1);
-                    }
-                }
-                continue;
-            }
-        }
-
-        if (!ovsdb_datum_is_default(datum, &column->type)) {
-            ds_put_char_multiple(&ctx->output, ' ', (level + 1) * 4);
-            ds_put_format(&ctx->output, "%s: ", column->name);
-            ovsdb_datum_to_string(datum, &column->type, &ctx->output);
-            ds_put_char(&ctx->output, '\n');
-        }
-    }
-    show->recurse = false;
-}
-
-static void
-cmd_show(struct ctl_context *ctx)
-{
-    const struct ovsdb_idl_row *row;
-
-    for (row = ovsdb_idl_first_row(ctx->idl, cmd_show_tables[0].table);
-         row; row = ovsdb_idl_next_row(row)) {
-        cmd_show_row(ctx, row, 0);
-    }
-}
+    {NULL, NULL, {NULL, NULL, NULL}, {NULL, NULL, NULL}}
+};
 
 static void
 pre_cmd_emer_reset(struct ctl_context *ctx)
@@ -1416,10 +1090,8 @@ cmd_emer_reset(struct ctl_context *ctx)
         /* We only want to save the "hwaddr" key from other_config. */
         hwaddr = smap_get(&br->other_config, "hwaddr");
         if (hwaddr) {
-            struct smap smap = SMAP_INITIALIZER(&smap);
-            smap_add(&smap, "hwaddr", hwaddr);
+            const struct smap smap = SMAP_CONST1(&smap, "hwaddr", hwaddr);
             ovsrec_bridge_set_other_config(br, &smap);
-            smap_destroy(&smap);
         } else {
             ovsrec_bridge_set_other_config(br, NULL);
         }
@@ -1685,7 +1357,7 @@ cmd_br_exists(struct ctl_context *ctx)
 
     vsctl_context_populate_cache(ctx);
     if (!find_bridge(vsctl_ctx, ctx->argv[1], false)) {
-        ctl_exit(2);
+        vsctl_exit(2);
     }
 }
 
@@ -1898,8 +1570,8 @@ add_port(struct ctl_context *ctx,
     }
 
     for (i = 0; i < n_settings; i++) {
-        set_column(get_table("Port"), &port->header_, settings[i],
-                   ctx->symtab);
+        ctl_set_column("Port", &port->header_, settings[i],
+                       ctx->symtab);
     }
 
     bridge_insert_port((bridge->parent ? bridge->parent->br_cfg
@@ -2479,7 +2151,7 @@ cmd_add_aa_mapping(struct ctl_context *ctx)
         br = br->parent;
     }
 
-    if (br && br->br_cfg) {
+    if (br->br_cfg) {
         if (!br->br_cfg->auto_attach) {
             struct ovsrec_autoattach *aa = ovsrec_autoattach_insert(ctx->txn);
             ovsrec_bridge_set_auto_attach(br->br_cfg, aa);
@@ -2539,7 +2211,7 @@ cmd_del_aa_mapping(struct ctl_context *ctx)
         br = br->parent;
     }
 
-    if (br && br->br_cfg && br->br_cfg->auto_attach &&
+    if (br->br_cfg && br->br_cfg->auto_attach &&
         br->br_cfg->auto_attach->key_mappings &&
         br->br_cfg->auto_attach->value_mappings) {
         size_t i;
@@ -2590,7 +2262,7 @@ cmd_get_aa_mapping(struct ctl_context *ctx)
 
     verify_auto_attach(br->br_cfg);
 
-    if (br && br->br_cfg && br->br_cfg->auto_attach &&
+    if (br->br_cfg && br->br_cfg->auto_attach &&
         br->br_cfg->auto_attach->key_mappings &&
         br->br_cfg->auto_attach->value_mappings) {
         size_t i;
@@ -2604,7 +2276,7 @@ cmd_get_aa_mapping(struct ctl_context *ctx)
 }
 
 \f
-const struct ctl_table_class tables[] = {
+static const struct ctl_table_class tables[] = {
     {&ovsrec_table_bridge,
      {{&ovsrec_table_bridge, &ovsrec_bridge_col_name, NULL},
       {&ovsrec_table_flow_sample_collector_set, NULL,
@@ -2795,6 +2467,44 @@ run_prerequisites(struct ctl_command *commands, size_t n_commands,
     }
 }
 
+static char *
+vsctl_parent_process_info(void)
+{
+#ifdef __linux__
+    pid_t parent_pid;
+    char *procfile;
+    struct ds s;
+    FILE *f;
+
+    parent_pid = getppid();
+    procfile = xasprintf("/proc/%d/cmdline", parent_pid);
+
+    f = fopen(procfile, "r");
+    if (!f) {
+        VLOG_WARN("%s: open failed (%s)", procfile, ovs_strerror(errno));
+        free(procfile);
+        return NULL;
+    }
+    free(procfile);
+
+    ds_init(&s);
+    for (;;) {
+        int c = getc(f);
+        if (!c || c == EOF) {
+            break;
+        }
+        ds_put_char(&s, c);
+    }
+    fclose(f);
+
+    ds_put_format(&s, " (pid %d)", parent_pid);
+
+    return ds_steal_cstr(&s);
+#else
+    return NULL;
+#endif
+}
+
 static void
 do_vsctl(const char *args, struct ctl_command *commands, size_t n_commands,
          struct ovsdb_idl *idl)
@@ -2808,13 +2518,21 @@ do_vsctl(const char *args, struct ctl_command *commands, size_t n_commands,
     struct shash_node *node;
     int64_t next_cfg = 0;
     char *error = NULL;
+    char *ppid_info = NULL;
 
     txn = the_idl_txn = ovsdb_idl_txn_create(idl);
     if (dry_run) {
         ovsdb_idl_txn_set_dry_run(txn);
     }
 
-    ovsdb_idl_txn_add_comment(txn, "ovs-vsctl: %s", args);
+    ppid_info = vsctl_parent_process_info();
+    if (ppid_info) {
+        ovsdb_idl_txn_add_comment(txn, "ovs-vsctl (invoked by %s): %s",
+                                  ppid_info, args);
+        free(ppid_info);
+    } else {
+        ovsdb_idl_txn_add_comment(txn, "ovs-vsctl: %s", args);
+    }
 
     ovs = ovsrec_open_vswitch_first(idl);
     if (!ovs) {
@@ -2990,6 +2708,23 @@ try_again:
     free(error);
 }
 
+/* Frees the current transaction and the underlying IDL and then calls
+ * exit(status).
+ *
+ * Freeing the transaction and the IDL is not strictly necessary, but it makes
+ * for a clean memory leak report from valgrind in the normal case.  That makes
+ * it easier to notice real memory leaks. */
+static void
+vsctl_exit(int status)
+{
+    if (the_idl_txn) {
+        ovsdb_idl_txn_abort(the_idl_txn);
+        ovsdb_idl_txn_destroy(the_idl_txn);
+    }
+    ovsdb_idl_destroy(the_idl);
+    exit(status);
+}
+
 /*
  * Developers who add new commands to the 'struct ctl_command_syntax' must
  * define the 'arguments' member of the struct.  The following keywords are
@@ -3011,7 +2746,6 @@ try_again:
 static const struct ctl_command_syntax vsctl_commands[] = {
     /* Open vSwitch commands. */
     {"init", 0, 0, "", NULL, cmd_init, NULL, "", RW},
-    {"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO},
 
     /* Bridge commands. */
     {"add-br", 1, 3, "NEW-BRIDGE [PARENT] [NEW-VLAN]", pre_get_info,
@@ -3092,6 +2826,6 @@ static const struct ctl_command_syntax vsctl_commands[] = {
 static void
 vsctl_cmd_init(void)
 {
-    ctl_init();
+    ctl_init(tables, cmd_show_tables, vsctl_exit);
     ctl_register_commands(vsctl_commands);
 }