stream-ssl: Improve messages when configuring SSL if it is unsupported.
[cascardo/ovs.git] / ovsdb / ovsdb-client.c
1 /*
2  * Copyright (c) 2009, 2010, 2011 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include <assert.h>
20 #include <errno.h>
21 #include <getopt.h>
22 #include <limits.h>
23 #include <signal.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "command-line.h"
29 #include "column.h"
30 #include "compiler.h"
31 #include "daemon.h"
32 #include "dynamic-string.h"
33 #include "json.h"
34 #include "jsonrpc.h"
35 #include "lib/table.h"
36 #include "ovsdb.h"
37 #include "ovsdb-data.h"
38 #include "ovsdb-error.h"
39 #include "sort.h"
40 #include "stream.h"
41 #include "stream-ssl.h"
42 #include "table.h"
43 #include "timeval.h"
44 #include "util.h"
45 #include "vlog.h"
46
47 VLOG_DEFINE_THIS_MODULE(ovsdb_client);
48
49 /* Format for table output. */
50 static struct table_style table_style = TABLE_STYLE_DEFAULT;
51
52 static const struct command all_commands[];
53
54 static void usage(void) NO_RETURN;
55 static void parse_options(int argc, char *argv[]);
56
57 int
58 main(int argc, char *argv[])
59 {
60     proctitle_init(argc, argv);
61     set_program_name(argv[0]);
62     parse_options(argc, argv);
63     signal(SIGPIPE, SIG_IGN);
64     run_command(argc - optind, argv + optind, all_commands);
65     return 0;
66 }
67
68 static void
69 parse_options(int argc, char *argv[])
70 {
71     enum {
72         OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
73         DAEMON_OPTION_ENUMS,
74         TABLE_OPTION_ENUMS
75     };
76     static struct option long_options[] = {
77         {"verbose", optional_argument, 0, 'v'},
78         {"help", no_argument, 0, 'h'},
79         {"version", no_argument, 0, 'V'},
80         DAEMON_LONG_OPTIONS,
81 #ifdef HAVE_OPENSSL
82         {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
83         STREAM_SSL_LONG_OPTIONS,
84 #endif
85         TABLE_LONG_OPTIONS,
86         {0, 0, 0, 0},
87     };
88     char *short_options = long_options_to_short_options(long_options);
89
90     for (;;) {
91         int c;
92
93         c = getopt_long(argc, argv, short_options, long_options, NULL);
94         if (c == -1) {
95             break;
96         }
97
98         switch (c) {
99         case 'h':
100             usage();
101
102         case 'V':
103             OVS_PRINT_VERSION(0, 0);
104             exit(EXIT_SUCCESS);
105
106         case 'v':
107             vlog_set_verbosity(optarg);
108             break;
109
110         DAEMON_OPTION_HANDLERS
111
112         TABLE_OPTION_HANDLERS(&table_style)
113
114         STREAM_SSL_OPTION_HANDLERS
115
116         case OPT_BOOTSTRAP_CA_CERT:
117             stream_ssl_set_ca_cert_file(optarg, true);
118             break;
119
120         case '?':
121             exit(EXIT_FAILURE);
122
123         case 0:
124             /* getopt_long() already set the value for us. */
125             break;
126
127         default:
128             abort();
129         }
130     }
131     free(short_options);
132 }
133
134 static void
135 usage(void)
136 {
137     printf("%s: Open vSwitch database JSON-RPC client\n"
138            "usage: %s [OPTIONS] COMMAND [ARG...]\n"
139            "\nValid commands are:\n"
140            "\n  list-dbs SERVER\n"
141            "    list databases available on SERVER\n"
142            "\n  get-schema SERVER DATABASE\n"
143            "    retrieve schema for DATABASE from SERVER\n"
144            "\n  get-schema-version SERVER DATABASE\n"
145            "    retrieve schema for DATABASE from SERVER and report only its\n"
146            "    version number on stdout\n"
147            "\n  list-tables SERVER DATABASE\n"
148            "    list tables for DATABASE on SERVER\n"
149            "\n  list-columns SERVER DATABASE [TABLE]\n"
150            "    list columns in TABLE (or all tables) in DATABASE on SERVER\n"
151            "\n  transact SERVER TRANSACTION\n"
152            "    run TRANSACTION (a JSON array of operations) on SERVER\n"
153            "    and print the results as JSON on stdout\n"
154            "\n  monitor SERVER DATABASE TABLE [COLUMN,...]...\n"
155            "    monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
156            "    COLUMNs may include !initial, !insert, !delete, !modify\n"
157            "    to avoid seeing the specified kinds of changes.\n"
158            "\n  dump SERVER DATABASE\n"
159            "    dump contents of DATABASE on SERVER to stdout\n",
160            program_name, program_name);
161     stream_usage("SERVER", true, true, true);
162     printf("\nOutput formatting options:\n"
163            "  -f, --format=FORMAT         set output formatting to FORMAT\n"
164            "                              (\"table\", \"html\", \"csv\", "
165            "or \"json\")\n"
166            "  --no-headings               omit table heading row\n"
167            "  --pretty                    pretty-print JSON in output");
168     daemon_usage();
169     vlog_usage();
170     printf("\nOther options:\n"
171            "  -h, --help                  display this help message\n"
172            "  -V, --version               display version information\n");
173     exit(EXIT_SUCCESS);
174 }
175 \f
176 static struct json *
177 parse_json(const char *s)
178 {
179     struct json *json = json_from_string(s);
180     if (json->type == JSON_STRING) {
181         ovs_fatal(0, "\"%s\": %s", s, json->u.string);
182     }
183     return json;
184 }
185
186 static struct jsonrpc *
187 open_jsonrpc(const char *server)
188 {
189     struct stream *stream;
190     int error;
191
192     error = stream_open_block(jsonrpc_stream_open(server, &stream), &stream);
193     if (error == EAFNOSUPPORT) {
194         struct pstream *pstream;
195
196         error = jsonrpc_pstream_open(server, &pstream);
197         if (error) {
198             ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
199         }
200
201         VLOG_INFO("%s: waiting for connection...", server);
202         error = pstream_accept_block(pstream, &stream);
203         if (error) {
204             ovs_fatal(error, "failed to accept connection on \"%s\"", server);
205         }
206
207         pstream_close(pstream);
208     } else if (error) {
209         ovs_fatal(error, "failed to connect to \"%s\"", server);
210     }
211
212     return jsonrpc_open(stream);
213 }
214
215 static void
216 print_json(struct json *json)
217 {
218     char *string = json_to_string(json, table_style.json_flags);
219     fputs(string, stdout);
220     free(string);
221 }
222
223 static void
224 print_and_free_json(struct json *json)
225 {
226     print_json(json);
227     json_destroy(json);
228 }
229
230 static void
231 check_ovsdb_error(struct ovsdb_error *error)
232 {
233     if (error) {
234         ovs_fatal(0, "%s", ovsdb_error_to_string(error));
235     }
236 }
237
238 static struct ovsdb_schema *
239 fetch_schema_from_rpc(struct jsonrpc *rpc, const char *database)
240 {
241     struct jsonrpc_msg *request, *reply;
242     struct ovsdb_schema *schema;
243     int error;
244
245     request = jsonrpc_create_request("get_schema",
246                                      json_array_create_1(
247                                          json_string_create(database)),
248                                      NULL);
249     error = jsonrpc_transact_block(rpc, request, &reply);
250     if (error) {
251         ovs_fatal(error, "transaction failed");
252     }
253     check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
254     jsonrpc_msg_destroy(reply);
255
256     return schema;
257 }
258
259 static struct ovsdb_schema *
260 fetch_schema(const char *server, const char *database)
261 {
262     struct ovsdb_schema *schema;
263     struct jsonrpc *rpc;
264
265     rpc = open_jsonrpc(server);
266     schema = fetch_schema_from_rpc(rpc, database);
267     jsonrpc_close(rpc);
268
269     return schema;
270 }
271 \f
272 \f
273 static void
274 do_list_dbs(int argc OVS_UNUSED, char *argv[])
275 {
276     struct jsonrpc_msg *request, *reply;
277     struct jsonrpc *rpc;
278     int error;
279     size_t i;
280
281     rpc = open_jsonrpc(argv[1]);
282     request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
283                                      NULL);
284     error = jsonrpc_transact_block(rpc, request, &reply);
285     if (error) {
286         ovs_fatal(error, "transaction failed");
287     }
288
289     if (reply->result->type != JSON_ARRAY) {
290         ovs_fatal(0, "list_dbs response is not array");
291     }
292
293     for (i = 0; i < reply->result->u.array.n; i++) {
294         const struct json *name = reply->result->u.array.elems[i];
295
296         if (name->type != JSON_STRING) {
297             ovs_fatal(0, "list_dbs response %zu is not string", i);
298         }
299         puts(name->u.string);
300     }
301     jsonrpc_msg_destroy(reply);
302 }
303
304 static void
305 do_get_schema(int argc OVS_UNUSED, char *argv[])
306 {
307     struct ovsdb_schema *schema = fetch_schema(argv[1], argv[2]);
308     print_and_free_json(ovsdb_schema_to_json(schema));
309     ovsdb_schema_destroy(schema);
310 }
311
312 static void
313 do_get_schema_version(int argc OVS_UNUSED, char *argv[])
314 {
315     struct ovsdb_schema *schema = fetch_schema(argv[1], argv[2]);
316     puts(schema->version);
317     ovsdb_schema_destroy(schema);
318 }
319
320 static void
321 do_list_tables(int argc OVS_UNUSED, char *argv[])
322 {
323     struct ovsdb_schema *schema;
324     struct shash_node *node;
325     struct table t;
326
327     schema = fetch_schema(argv[1], argv[2]);
328     table_init(&t);
329     table_add_column(&t, "Table");
330     SHASH_FOR_EACH (node, &schema->tables) {
331         struct ovsdb_table_schema *ts = node->data;
332
333         table_add_row(&t);
334         table_add_cell(&t)->text = xstrdup(ts->name);
335     }
336     ovsdb_schema_destroy(schema);
337     table_print(&t, &table_style);
338 }
339
340 static void
341 do_list_columns(int argc OVS_UNUSED, char *argv[])
342 {
343     const char *table_name = argv[3];
344     struct ovsdb_schema *schema;
345     struct shash_node *table_node;
346     struct table t;
347
348     schema = fetch_schema(argv[1], argv[2]);
349     table_init(&t);
350     if (!table_name) {
351         table_add_column(&t, "Table");
352     }
353     table_add_column(&t, "Column");
354     table_add_column(&t, "Type");
355     SHASH_FOR_EACH (table_node, &schema->tables) {
356         struct ovsdb_table_schema *ts = table_node->data;
357
358         if (!table_name || !strcmp(table_name, ts->name)) {
359             struct shash_node *column_node;
360
361             SHASH_FOR_EACH (column_node, &ts->columns) {
362                 const struct ovsdb_column *column = column_node->data;
363
364                 table_add_row(&t);
365                 if (!table_name) {
366                     table_add_cell(&t)->text = xstrdup(ts->name);
367                 }
368                 table_add_cell(&t)->text = xstrdup(column->name);
369                 table_add_cell(&t)->json = ovsdb_type_to_json(&column->type);
370             }
371         }
372     }
373     ovsdb_schema_destroy(schema);
374     table_print(&t, &table_style);
375 }
376
377 static void
378 do_transact(int argc OVS_UNUSED, char *argv[])
379 {
380     struct jsonrpc_msg *request, *reply;
381     struct json *transaction;
382     struct jsonrpc *rpc;
383     int error;
384
385     transaction = parse_json(argv[2]);
386
387     rpc = open_jsonrpc(argv[1]);
388     request = jsonrpc_create_request("transact", transaction, NULL);
389     error = jsonrpc_transact_block(rpc, request, &reply);
390     if (error) {
391         ovs_fatal(error, "transaction failed");
392     }
393     if (reply->error) {
394         ovs_fatal(error, "transaction returned error: %s",
395                   json_to_string(reply->error, table_style.json_flags));
396     }
397     print_json(reply->result);
398     putchar('\n');
399     jsonrpc_msg_destroy(reply);
400     jsonrpc_close(rpc);
401 }
402
403 static void
404 monitor_print_row(struct json *row, const char *type, const char *uuid,
405                   const struct ovsdb_column_set *columns, struct table *t)
406 {
407     size_t i;
408
409     if (!row) {
410         ovs_error(0, "missing %s row", type);
411         return;
412     } else if (row->type != JSON_OBJECT) {
413         ovs_error(0, "<row> is not object");
414         return;
415     }
416
417     table_add_row(t);
418     table_add_cell(t)->text = xstrdup(uuid);
419     table_add_cell(t)->text = xstrdup(type);
420     for (i = 0; i < columns->n_columns; i++) {
421         const struct ovsdb_column *column = columns->columns[i];
422         struct json *value = shash_find_data(json_object(row), column->name);
423         struct cell *cell = table_add_cell(t);
424         if (value) {
425             cell->json = json_clone(value);
426             cell->type = &column->type;
427         }
428     }
429 }
430
431 static void
432 monitor_print(struct json *table_updates,
433               const struct ovsdb_table_schema *table,
434               const struct ovsdb_column_set *columns, bool initial)
435 {
436     struct json *table_update;
437     struct shash_node *node;
438     struct table t;
439     size_t i;
440
441     table_init(&t);
442
443     if (table_updates->type != JSON_OBJECT) {
444         ovs_error(0, "<table-updates> is not object");
445         return;
446     }
447     table_update = shash_find_data(json_object(table_updates), table->name);
448     if (!table_update) {
449         return;
450     }
451     if (table_update->type != JSON_OBJECT) {
452         ovs_error(0, "<table-update> is not object");
453         return;
454     }
455
456     table_add_column(&t, "row");
457     table_add_column(&t, "action");
458     for (i = 0; i < columns->n_columns; i++) {
459         table_add_column(&t, "%s", columns->columns[i]->name);
460     }
461     SHASH_FOR_EACH (node, json_object(table_update)) {
462         struct json *row_update = node->data;
463         struct json *old, *new;
464
465         if (row_update->type != JSON_OBJECT) {
466             ovs_error(0, "<row-update> is not object");
467             continue;
468         }
469         old = shash_find_data(json_object(row_update), "old");
470         new = shash_find_data(json_object(row_update), "new");
471         if (initial) {
472             monitor_print_row(new, "initial", node->name, columns, &t);
473         } else if (!old) {
474             monitor_print_row(new, "insert", node->name, columns, &t);
475         } else if (!new) {
476             monitor_print_row(old, "delete", node->name, columns, &t);
477         } else {
478             monitor_print_row(old, "old", node->name, columns, &t);
479             monitor_print_row(new, "new", "", columns, &t);
480         }
481     }
482     table_print(&t, &table_style);
483     table_destroy(&t);
484 }
485
486 static void
487 add_column(const char *server, const struct ovsdb_column *column,
488            struct ovsdb_column_set *columns, struct json *columns_json)
489 {
490     if (ovsdb_column_set_contains(columns, column->index)) {
491         ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
492                   server, column->name);
493     }
494     ovsdb_column_set_add(columns, column);
495     json_array_add(columns_json, json_string_create(column->name));
496 }
497
498 static struct json *
499 parse_monitor_columns(char *arg, const char *server, const char *database,
500                       const struct ovsdb_table_schema *table,
501                       struct ovsdb_column_set *columns)
502 {
503     bool initial, insert, delete, modify;
504     struct json *mr, *columns_json;
505     char *save_ptr = NULL;
506     char *token;
507
508     mr = json_object_create();
509     columns_json = json_array_create_empty();
510     json_object_put(mr, "columns", columns_json);
511
512     initial = insert = delete = modify = true;
513     for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
514          token = strtok_r(NULL, ",", &save_ptr)) {
515         if (!strcmp(token, "!initial")) {
516             initial = false;
517         } else if (!strcmp(token, "!insert")) {
518             insert = false;
519         } else if (!strcmp(token, "!delete")) {
520             delete = false;
521         } else if (!strcmp(token, "!modify")) {
522             modify = false;
523         } else {
524             const struct ovsdb_column *column;
525
526             column = ovsdb_table_schema_get_column(table, token);
527             if (!column) {
528                 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
529                           "column named \"%s\"",
530                           server, table->name, database, token);
531             }
532             add_column(server, column, columns, columns_json);
533         }
534     }
535
536     if (columns_json->u.array.n == 0) {
537         const struct shash_node **nodes;
538         size_t i, n;
539
540         n = shash_count(&table->columns);
541         nodes = shash_sort(&table->columns);
542         for (i = 0; i < n; i++) {
543             const struct ovsdb_column *column = nodes[i]->data;
544             if (column->index != OVSDB_COL_UUID
545                 && column->index != OVSDB_COL_VERSION) {
546                 add_column(server, column, columns, columns_json);
547             }
548         }
549         free(nodes);
550
551         add_column(server, ovsdb_table_schema_get_column(table,"_version"),
552                    columns, columns_json);
553     }
554
555     if (!initial || !insert || !delete || !modify) {
556         struct json *select = json_object_create();
557         json_object_put(select, "initial", json_boolean_create(initial));
558         json_object_put(select, "insert", json_boolean_create(insert));
559         json_object_put(select, "delete", json_boolean_create(delete));
560         json_object_put(select, "modify", json_boolean_create(modify));
561         json_object_put(mr, "select", select);
562     }
563
564     return mr;
565 }
566
567 static void
568 do_monitor(int argc, char *argv[])
569 {
570     const char *server = argv[1];
571     const char *database = argv[2];
572     const char *table_name = argv[3];
573     struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
574     struct ovsdb_table_schema *table;
575     struct ovsdb_schema *schema;
576     struct jsonrpc_msg *request;
577     struct jsonrpc *rpc;
578     struct json *monitor, *monitor_request_array,
579         *monitor_requests, *request_id;
580
581     rpc = open_jsonrpc(server);
582
583     schema = fetch_schema_from_rpc(rpc, database);
584     table = shash_find_data(&schema->tables, table_name);
585     if (!table) {
586         ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
587                   server, database, table_name);
588     }
589
590     monitor_request_array = json_array_create_empty();
591     if (argc > 4) {
592         int i;
593
594         for (i = 4; i < argc; i++) {
595             json_array_add(
596                 monitor_request_array,
597                 parse_monitor_columns(argv[i], server, database, table,
598                                       &columns));
599         }
600     } else {
601         /* Allocate a writable empty string since parse_monitor_columns() is
602          * going to strtok() it and that's risky with literal "". */
603         char empty[] = "";
604         json_array_add(
605             monitor_request_array,
606             parse_monitor_columns(empty, server, database, table, &columns));
607     }
608
609     monitor_requests = json_object_create();
610     json_object_put(monitor_requests, table_name, monitor_request_array);
611
612     monitor = json_array_create_3(json_string_create(database),
613                                   json_null_create(), monitor_requests);
614     request = jsonrpc_create_request("monitor", monitor, NULL);
615     request_id = json_clone(request->id);
616     jsonrpc_send(rpc, request);
617     for (;;) {
618         struct jsonrpc_msg *msg;
619         int error;
620
621         error = jsonrpc_recv_block(rpc, &msg);
622         if (error) {
623             ovsdb_schema_destroy(schema);
624             ovs_fatal(error, "%s: receive failed", server);
625         }
626
627         if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
628             jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
629                                                    msg->id));
630         } else if (msg->type == JSONRPC_REPLY
631                    && json_equal(msg->id, request_id)) {
632             monitor_print(msg->result, table, &columns, true);
633             fflush(stdout);
634             if (get_detach()) {
635                 /* daemonize() closes the standard file descriptors.  We output
636                  * to stdout, so we need to save and restore STDOUT_FILENO. */
637                 int fd = dup(STDOUT_FILENO);
638                 daemonize();
639                 dup2(fd, STDOUT_FILENO);
640                 close(fd);
641             }
642         } else if (msg->type == JSONRPC_NOTIFY
643                    && !strcmp(msg->method, "update")) {
644             struct json *params = msg->params;
645             if (params->type == JSON_ARRAY
646                 && params->u.array.n == 2
647                 && params->u.array.elems[0]->type == JSON_NULL) {
648                 monitor_print(params->u.array.elems[1],
649                               table, &columns, false);
650                 fflush(stdout);
651             }
652         }
653         jsonrpc_msg_destroy(msg);
654     }
655 }
656
657 struct dump_table_aux {
658     struct ovsdb_datum **data;
659     const struct ovsdb_column **columns;
660     size_t n_columns;
661 };
662
663 static int
664 compare_data(size_t a_y, size_t b_y, size_t x,
665              const struct dump_table_aux *aux)
666 {
667     return ovsdb_datum_compare_3way(&aux->data[a_y][x],
668                                     &aux->data[b_y][x],
669                                     &aux->columns[x]->type);
670 }
671
672 static int
673 compare_rows(size_t a_y, size_t b_y, void *aux_)
674 {
675     struct dump_table_aux *aux = aux_;
676     size_t x;
677
678     /* Skip UUID columns on the first pass, since their values tend to be
679      * random and make our results less reproducible. */
680     for (x = 0; x < aux->n_columns; x++) {
681         if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
682             int cmp = compare_data(a_y, b_y, x, aux);
683             if (cmp) {
684                 return cmp;
685             }
686         }
687     }
688
689     /* Use UUID columns as tie-breakers. */
690     for (x = 0; x < aux->n_columns; x++) {
691         if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
692             int cmp = compare_data(a_y, b_y, x, aux);
693             if (cmp) {
694                 return cmp;
695             }
696         }
697     }
698
699     return 0;
700 }
701
702 static void
703 swap_rows(size_t a_y, size_t b_y, void *aux_)
704 {
705     struct dump_table_aux *aux = aux_;
706     struct ovsdb_datum *tmp = aux->data[a_y];
707     aux->data[a_y] = aux->data[b_y];
708     aux->data[b_y] = tmp;
709 }
710
711 static int
712 compare_columns(const void *a_, const void *b_)
713 {
714     const struct ovsdb_column *const *ap = a_;
715     const struct ovsdb_column *const *bp = b_;
716     const struct ovsdb_column *a = *ap;
717     const struct ovsdb_column *b = *bp;
718
719     return strcmp(a->name, b->name);
720 }
721
722 static void
723 dump_table(const struct ovsdb_table_schema *ts, struct json_array *rows)
724 {
725     const struct ovsdb_column **columns;
726     size_t n_columns;
727
728     struct ovsdb_datum **data;
729
730     struct dump_table_aux aux;
731     struct shash_node *node;
732     struct table t;
733     size_t x, y;
734
735     /* Sort columns by name, for reproducibility. */
736     columns = xmalloc(shash_count(&ts->columns) * sizeof *columns);
737     n_columns = 0;
738     SHASH_FOR_EACH (node, &ts->columns) {
739         struct ovsdb_column *column = node->data;
740         if (strcmp(column->name, "_version")) {
741             columns[n_columns++] = column;
742         }
743     }
744     qsort(columns, n_columns, sizeof *columns, compare_columns);
745
746     /* Extract data from table. */
747     data = xmalloc(rows->n * sizeof *data);
748     for (y = 0; y < rows->n; y++) {
749         struct shash *row;
750
751         if (rows->elems[y]->type != JSON_OBJECT) {
752             ovs_fatal(0,  "row %zu in table %s response is not a JSON object: "
753                       "%s", y, ts->name, json_to_string(rows->elems[y], 0));
754         }
755         row = json_object(rows->elems[y]);
756
757         data[y] = xmalloc(n_columns * sizeof **data);
758         for (x = 0; x < n_columns; x++) {
759             const struct json *json = shash_find_data(row, columns[x]->name);
760             if (!json) {
761                 ovs_fatal(0, "row %zu in table %s response lacks %s column",
762                           y, ts->name, columns[x]->name);
763             }
764
765             check_ovsdb_error(ovsdb_datum_from_json(&data[y][x],
766                                                     &columns[x]->type,
767                                                     json, NULL));
768         }
769     }
770
771     /* Sort rows by column values, for reproducibility. */
772     aux.data = data;
773     aux.columns = columns;
774     aux.n_columns = n_columns;
775     sort(rows->n, compare_rows, swap_rows, &aux);
776
777     /* Add column headings. */
778     table_init(&t);
779     table_set_caption(&t, xasprintf("%s table", ts->name));
780     for (x = 0; x < n_columns; x++) {
781         table_add_column(&t, "%s", columns[x]->name);
782     }
783
784     /* Print rows. */
785     for (y = 0; y < rows->n; y++) {
786         table_add_row(&t);
787         for (x = 0; x < n_columns; x++) {
788             struct cell *cell = table_add_cell(&t);
789             cell->json = ovsdb_datum_to_json(&data[y][x], &columns[x]->type);
790             cell->type = &columns[x]->type;
791         }
792     }
793     table_print(&t, &table_style);
794     table_destroy(&t);
795 }
796
797 static void
798 do_dump(int argc OVS_UNUSED, char *argv[])
799 {
800     const char *server = argv[1];
801     const char *database = argv[2];
802
803     struct jsonrpc_msg *request, *reply;
804     struct ovsdb_schema *schema;
805     struct json *transaction;
806     struct jsonrpc *rpc;
807     int error;
808
809     const struct shash_node **tables;
810     size_t n_tables;
811
812     size_t i;
813
814     rpc = open_jsonrpc(server);
815
816     schema = fetch_schema_from_rpc(rpc, database);
817     tables = shash_sort(&schema->tables);
818     n_tables = shash_count(&schema->tables);
819
820     /* Construct transaction to retrieve entire database. */
821     transaction = json_array_create_1(json_string_create(database));
822     for (i = 0; i < n_tables; i++) {
823         const struct ovsdb_table_schema *ts = tables[i]->data;
824         struct json *op, *columns;
825         struct shash_node *node;
826
827         columns = json_array_create_empty();
828         SHASH_FOR_EACH (node, &ts->columns) {
829             const struct ovsdb_column *column = node->data;
830
831             if (strcmp(column->name, "_version")) {
832                 json_array_add(columns, json_string_create(column->name));
833             }
834         }
835
836         op = json_object_create();
837         json_object_put_string(op, "op", "select");
838         json_object_put_string(op, "table", tables[i]->name);
839         json_object_put(op, "where", json_array_create_empty());
840         json_object_put(op, "columns", columns);
841         json_array_add(transaction, op);
842     }
843
844     /* Send request, get reply. */
845     request = jsonrpc_create_request("transact", transaction, NULL);
846     error = jsonrpc_transact_block(rpc, request, &reply);
847     if (error) {
848         ovs_fatal(error, "transaction failed");
849     }
850
851     /* Print database contents. */
852     if (reply->result->type != JSON_ARRAY
853         || reply->result->u.array.n != n_tables) {
854         ovs_fatal(0, "reply is not array of %zu elements: %s",
855                   n_tables, json_to_string(reply->result, 0));
856     }
857     for (i = 0; i < n_tables; i++) {
858         const struct ovsdb_table_schema *ts = tables[i]->data;
859         const struct json *op_result = reply->result->u.array.elems[i];
860         struct json *rows;
861
862         if (op_result->type != JSON_OBJECT
863             || !(rows = shash_find_data(json_object(op_result), "rows"))
864             || rows->type != JSON_ARRAY) {
865             ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
866                       "member array: %s",
867                       ts->name, json_to_string(op_result, 0));
868         }
869
870         dump_table(ts, &rows->u.array);
871     }
872 }
873
874 static void
875 do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
876 {
877     usage();
878 }
879
880 static const struct command all_commands[] = {
881     { "list-dbs", 1, 1, do_list_dbs },
882     { "get-schema", 2, 2, do_get_schema },
883     { "get-schema-version", 2, 2, do_get_schema_version },
884     { "list-tables", 2, 2, do_list_tables },
885     { "list-columns", 2, 3, do_list_columns },
886     { "transact", 2, 2, do_transact },
887     { "monitor", 3, INT_MAX, do_monitor },
888     { "dump", 2, 2, do_dump },
889     { "help", 0, INT_MAX, do_help },
890     { NULL, 0, 0, NULL },
891 };