ovsdb-server: Refactoring and clean up remote status reporting.
[cascardo/ovs.git] / ovsdb / ovsdb-tool.c
index f680989..32883e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
 #include "compiler.h"
 #include "dirs.h"
 #include "dynamic-string.h"
+#include "fatal-signal.h"
 #include "file.h"
 #include "lockfile.h"
 #include "log.h"
 #include "table.h"
 #include "timeval.h"
 #include "util.h"
-#include "vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(ovsdb_tool);
+#include "openvswitch/vlog.h"
 
 /* -m, --more: Verbosity level for "show-log" command output. */
 static int show_log_verbosity;
 
-static const struct command all_commands[];
+static const struct ovs_cmdl_command *get_all_commands(void);
 
-static void usage(void) NO_RETURN;
+OVS_NO_RETURN static void usage(void);
 static void parse_options(int argc, char *argv[]);
 
 static const char *default_db(void);
@@ -56,24 +55,28 @@ static const char *default_schema(void);
 int
 main(int argc, char *argv[])
 {
+    struct ovs_cmdl_context ctx = { .argc = 0, };
     set_program_name(argv[0]);
     parse_options(argc, argv);
-    signal(SIGPIPE, SIG_IGN);
-    run_command(argc - optind, argv + optind, all_commands);
+    fatal_ignore_sigpipe();
+    ctx.argc = argc - optind;
+    ctx.argv = argv + optind;
+    ovs_cmdl_run_command(&ctx, get_all_commands());
     return 0;
 }
 
 static void
 parse_options(int argc, char *argv[])
 {
-    static struct option long_options[] = {
+    static const struct option long_options[] = {
         {"more", no_argument, NULL, 'm'},
         {"verbose", optional_argument, NULL, 'v'},
         {"help", no_argument, NULL, 'h'},
+        {"option", no_argument, NULL, 'o'},
         {"version", no_argument, NULL, 'V'},
         {NULL, 0, NULL, 0},
     };
-    char *short_options = long_options_to_short_options(long_options);
+    char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
 
     for (;;) {
         int c;
@@ -91,6 +94,10 @@ parse_options(int argc, char *argv[])
         case 'h':
             usage();
 
+        case 'o':
+            ovs_cmdl_print_options(long_options);
+            exit(EXIT_SUCCESS);
+
         case 'V':
             ovs_print_version(0, 0);
             exit(EXIT_SUCCESS);
@@ -140,7 +147,7 @@ default_db(void)
 {
     static char *db;
     if (!db) {
-        db = xasprintf("%s/conf.db", ovs_sysconfdir());
+        db = xasprintf("%s/conf.db", ovs_dbdir());
     }
     return db;
 }
@@ -183,10 +190,10 @@ check_ovsdb_error(struct ovsdb_error *error)
 }
 \f
 static void
-do_create(int argc, char *argv[])
+do_create(struct ovs_cmdl_context *ctx)
 {
-    const char *db_file_name = argc >= 2 ? argv[1] : default_db();
-    const char *schema_file_name = argc >= 3 ? argv[2] : default_schema();
+    const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
+    const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : default_schema();
     struct ovsdb_schema *schema;
     struct ovsdb_log *log;
     struct json *json;
@@ -207,29 +214,36 @@ do_create(int argc, char *argv[])
 }
 
 static void
-compact_or_convert(const char *src_name, const char *dst_name,
+compact_or_convert(const char *src_name_, const char *dst_name_,
                    const struct ovsdb_schema *new_schema,
                    const char *comment)
 {
+    char *src_name, *dst_name;
     struct lockfile *src_lock;
     struct lockfile *dst_lock;
-    bool in_place = dst_name == NULL;
+    bool in_place = dst_name_ == NULL;
     struct ovsdb *db;
     int retval;
 
+    /* Dereference symlinks for source and destination names.  In the in-place
+     * case this ensures that, if the source name is a symlink, we replace its
+     * target instead of replacing the symlink by a regular file.  In the
+     * non-in-place, this has the same effect for the destination name. */
+    src_name = follow_symlinks(src_name_);
+    dst_name = (in_place
+                ? xasprintf("%s.tmp", src_name)
+                : follow_symlinks(dst_name_));
+
     /* Lock the source, if we will be replacing it. */
     if (in_place) {
-        retval = lockfile_lock(src_name, 0, &src_lock);
+        retval = lockfile_lock(src_name, &src_lock);
         if (retval) {
             ovs_fatal(retval, "%s: failed to lock lockfile", src_name);
         }
     }
 
     /* Get (temporary) destination and lock it. */
-    if (in_place) {
-        dst_name = xasprintf("%s.tmp", src_name);
-    }
-    retval = lockfile_lock(dst_name, 0, &dst_lock);
+    retval = lockfile_lock(dst_name, &dst_lock);
     if (retval) {
         ovs_fatal(retval, "%s: failed to lock lockfile", dst_name);
     }
@@ -243,6 +257,9 @@ compact_or_convert(const char *src_name, const char *dst_name,
 
     /* Replace source. */
     if (in_place) {
+#ifdef _WIN32
+        unlink(src_name);
+#endif
         if (rename(dst_name, src_name)) {
             ovs_fatal(errno, "failed to rename \"%s\" to \"%s\"",
                       dst_name, src_name);
@@ -253,26 +270,25 @@ compact_or_convert(const char *src_name, const char *dst_name,
 
     lockfile_unlock(dst_lock);
 
-    if (in_place) {
-        free((char *) dst_name);
-    }
+    free(src_name);
+    free(dst_name);
 }
 
 static void
-do_compact(int argc, char *argv[])
+do_compact(struct ovs_cmdl_context *ctx)
 {
-    const char *db = argc >= 2 ? argv[1] : default_db();
-    const char *target = argc >= 3 ? argv[2] : NULL;
+    const char *db = ctx->argc >= 2 ? ctx->argv[1] : default_db();
+    const char *target = ctx->argc >= 3 ? ctx->argv[2] : NULL;
 
     compact_or_convert(db, target, NULL, "compacted by ovsdb-tool "VERSION);
 }
 
 static void
-do_convert(int argc, char *argv[])
+do_convert(struct ovs_cmdl_context *ctx)
 {
-    const char *db = argc >= 2 ? argv[1] : default_db();
-    const char *schema = argc >= 3 ? argv[2] : default_schema();
-    const char *target = argc >= 4 ? argv[3] : NULL;
+    const char *db = ctx->argc >= 2 ? ctx->argv[1] : default_db();
+    const char *schema = ctx->argc >= 3 ? ctx->argv[2] : default_schema();
+    const char *target = ctx->argc >= 4 ? ctx->argv[3] : NULL;
     struct ovsdb_schema *new_schema;
 
     check_ovsdb_error(ovsdb_schema_from_file(schema, &new_schema));
@@ -282,10 +298,10 @@ do_convert(int argc, char *argv[])
 }
 
 static void
-do_needs_conversion(int argc, char *argv[])
+do_needs_conversion(struct ovs_cmdl_context *ctx)
 {
-    const char *db_file_name = argc >= 2 ? argv[1] : default_db();
-    const char *schema_file_name = argc >= 3 ? argv[2] : default_schema();
+    const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
+    const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : default_schema();
     struct ovsdb_schema *schema1, *schema2;
 
     check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema1));
@@ -296,9 +312,9 @@ do_needs_conversion(int argc, char *argv[])
 }
 
 static void
-do_db_version(int argc, char *argv[])
+do_db_version(struct ovs_cmdl_context *ctx)
 {
-    const char *db_file_name = argc >= 2 ? argv[1] : default_db();
+    const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
     struct ovsdb_schema *schema;
 
     check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema));
@@ -307,9 +323,9 @@ do_db_version(int argc, char *argv[])
 }
 
 static void
-do_db_cksum(int argc OVS_UNUSED, char *argv[])
+do_db_cksum(struct ovs_cmdl_context *ctx)
 {
-    const char *db_file_name = argc >= 2 ? argv[1] : default_db();
+    const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
     struct ovsdb_schema *schema;
 
     check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema));
@@ -318,9 +334,9 @@ do_db_cksum(int argc OVS_UNUSED, char *argv[])
 }
 
 static void
-do_schema_version(int argc, char *argv[])
+do_schema_version(struct ovs_cmdl_context *ctx)
 {
-    const char *schema_file_name = argc >= 2 ? argv[1] : default_schema();
+    const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_schema();
     struct ovsdb_schema *schema;
 
     check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema));
@@ -329,9 +345,9 @@ do_schema_version(int argc, char *argv[])
 }
 
 static void
-do_schema_cksum(int argc, char *argv[])
+do_schema_cksum(struct ovs_cmdl_context *ctx)
 {
-    const char *schema_file_name = argc >= 2 ? argv[1] : default_schema();
+    const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_schema();
     struct ovsdb_schema *schema;
 
     check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema));
@@ -358,15 +374,15 @@ transact(bool read_only, int argc, char *argv[])
 }
 
 static void
-do_query(int argc, char *argv[])
+do_query(struct ovs_cmdl_context *ctx)
 {
-    transact(true, argc, argv);
+    transact(true, ctx->argc, ctx->argv);
 }
 
 static void
-do_transact(int argc, char *argv[])
+do_transact(struct ovs_cmdl_context *ctx)
 {
-    transact(false, argc, argv);
+    transact(false, ctx->argc, ctx->argv);
 }
 
 static void
@@ -429,8 +445,8 @@ print_db_changes(struct shash *tables, struct shash *names,
                              ? shash_find_data(&table_schema->columns, column)
                              : NULL);
                         if (column_schema) {
-                            const struct ovsdb_error *error;
                             const struct ovsdb_type *type;
+                            struct ovsdb_error *error;
                             struct ovsdb_datum datum;
 
                             type = &column_schema->type;
@@ -442,6 +458,8 @@ print_db_changes(struct shash *tables, struct shash *names,
                                 ds_init(&s);
                                 ovsdb_datum_to_string(&datum, type, &s);
                                 value_string = ds_steal_cstr(&s);
+                            } else {
+                                ovsdb_error_destroy(error);
                             }
                         }
                         if (!value_string) {
@@ -480,9 +498,9 @@ print_db_changes(struct shash *tables, struct shash *names,
 }
 
 static void
-do_show_log(int argc, char *argv[])
+do_show_log(struct ovs_cmdl_context *ctx)
 {
-    const char *db_file_name = argc >= 2 ? argv[1] : default_db();
+    const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db();
     struct shash names;
     struct ovsdb_log *log;
     struct ovsdb_schema *schema;
@@ -510,11 +528,17 @@ do_show_log(int argc, char *argv[])
 
             date = shash_find_data(json_object(json), "_date");
             if (date && date->type == JSON_INTEGER) {
-                time_t t = json_integer(date);
-                char s[128];
+                long long int t = json_integer(date);
+                char *s;
 
-                strftime(s, sizeof s, "%Y-%m-%d %H:%M:%S", localtime(&t));
-                printf(" %s", s);
+                if (t < INT32_MAX) {
+                    /* Older versions of ovsdb wrote timestamps in seconds. */
+                    t *= 1000;
+                }
+
+                s = xastrftime_msec(" %Y-%m-%d %H:%M:%S.###", t, true);
+                fputs(s, stdout);
+                free(s);
             }
 
             comment = shash_find_data(json_object(json), "_comment");
@@ -537,23 +561,35 @@ do_show_log(int argc, char *argv[])
 }
 
 static void
-do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+do_help(struct ovs_cmdl_context *ctx OVS_UNUSED)
 {
     usage();
 }
 
-static const struct command all_commands[] = {
-    { "create", 0, 2, do_create },
-    { "compact", 0, 2, do_compact },
-    { "convert", 0, 3, do_convert },
-    { "needs-conversion", 0, 2, do_needs_conversion },
-    { "db-version", 0, 1, do_db_version },
-    { "db-cksum", 0, 1, do_db_cksum },
-    { "schema-version", 0, 1, do_schema_version },
-    { "schema-cksum", 0, 1, do_schema_cksum },
-    { "query", 1, 2, do_query },
-    { "transact", 1, 2, do_transact },
-    { "show-log", 0, 1, do_show_log },
-    { "help", 0, INT_MAX, do_help },
-    { NULL, 0, 0, NULL },
+static void
+do_list_commands(struct ovs_cmdl_context *ctx OVS_UNUSED)
+{
+     ovs_cmdl_print_commands(get_all_commands());
+}
+
+static const struct ovs_cmdl_command all_commands[] = {
+    { "create", "[db [schema]]", 0, 2, do_create },
+    { "compact", "[db [dst]]", 0, 2, do_compact },
+    { "convert", "[db [schema [dst]]]", 0, 3, do_convert },
+    { "needs-conversion", NULL, 0, 2, do_needs_conversion },
+    { "db-version", "[db]",  0, 1, do_db_version },
+    { "db-cksum", "[db]", 0, 1, do_db_cksum },
+    { "schema-version", "[schema]", 0, 1, do_schema_version },
+    { "schema-cksum", "[schema]", 0, 1, do_schema_cksum },
+    { "query", "[db] trns", 1, 2, do_query },
+    { "transact", "[db] trns", 1, 2, do_transact },
+    { "show-log", "[db]", 0, 1, do_show_log },
+    { "help", NULL, 0, INT_MAX, do_help },
+    { "list-commands", NULL, 0, INT_MAX, do_list_commands },
+    { NULL, NULL, 0, 0, NULL },
 };
+
+static const struct ovs_cmdl_command *get_all_commands(void)
+{
+    return all_commands;
+}