ovsdb-client: Make "dump" print table names in default output format too.
[cascardo/ovs.git] / ovsdb / ovsdb-client.c
1 /*
2  * Copyright (c) 2009, 2010 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 "ovsdb.h"
36 #include "ovsdb-data.h"
37 #include "ovsdb-error.h"
38 #include "sort.h"
39 #include "stream.h"
40 #include "stream-ssl.h"
41 #include "table.h"
42 #include "timeval.h"
43 #include "util.h"
44 #include "vlog.h"
45
46 VLOG_DEFINE_THIS_MODULE(ovsdb_client)
47
48 /* --format: Output formatting. */
49 static enum {
50     FMT_TABLE,                  /* Textual table. */
51     FMT_HTML,                   /* HTML table. */
52     FMT_CSV                     /* Comma-separated lines. */
53 } output_format;
54
55 /* --no-headings: Whether table output should include headings. */
56 static int output_headings = true;
57
58 /* --pretty: Flags to pass to json_to_string(). */
59 static int json_flags = JSSF_SORT;
60
61 /* --data: Format of data in output tables. */
62 static enum {
63     DF_STRING,                  /* String format. */
64     DF_JSON,                    /* JSON. */
65 } data_format;
66
67 static const struct command all_commands[];
68
69 static void usage(void) NO_RETURN;
70 static void parse_options(int argc, char *argv[]);
71
72 int
73 main(int argc, char *argv[])
74 {
75     proctitle_init(argc, argv);
76     set_program_name(argv[0]);
77     parse_options(argc, argv);
78     signal(SIGPIPE, SIG_IGN);
79     run_command(argc - optind, argv + optind, all_commands);
80     return 0;
81 }
82
83 static void
84 parse_options(int argc, char *argv[])
85 {
86     enum {
87         OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1
88     };
89     static struct option long_options[] = {
90         {"format", required_argument, 0, 'f'},
91         {"data", required_argument, 0, 'd'},
92         {"no-headings", no_argument, &output_headings, 0},
93         {"pretty", no_argument, &json_flags, JSSF_PRETTY | JSSF_SORT},
94         {"verbose", optional_argument, 0, 'v'},
95         {"help", no_argument, 0, 'h'},
96         {"version", no_argument, 0, 'V'},
97         DAEMON_LONG_OPTIONS,
98 #ifdef HAVE_OPENSSL
99         {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
100         STREAM_SSL_LONG_OPTIONS
101 #endif
102         {0, 0, 0, 0},
103     };
104     char *short_options = long_options_to_short_options(long_options);
105
106     for (;;) {
107         int c;
108
109         c = getopt_long(argc, argv, short_options, long_options, NULL);
110         if (c == -1) {
111             break;
112         }
113
114         switch (c) {
115         case 'f':
116             if (!strcmp(optarg, "table")) {
117                 output_format = FMT_TABLE;
118             } else if (!strcmp(optarg, "html")) {
119                 output_format = FMT_HTML;
120             } else if (!strcmp(optarg, "csv")) {
121                 output_format = FMT_CSV;
122             } else {
123                 ovs_fatal(0, "unknown output format \"%s\"", optarg);
124             }
125             break;
126
127         case 'd':
128             if (!strcmp(optarg, "string")) {
129                 data_format = DF_STRING;
130             } else if (!strcmp(optarg, "json")) {
131                 data_format = DF_JSON;
132             } else {
133                 ovs_fatal(0, "unknown data format \"%s\"", optarg);
134             }
135             break;
136
137         case 'h':
138             usage();
139
140         case 'V':
141             OVS_PRINT_VERSION(0, 0);
142             exit(EXIT_SUCCESS);
143
144         case 'v':
145             vlog_set_verbosity(optarg);
146             break;
147
148         DAEMON_OPTION_HANDLERS
149
150 #ifdef HAVE_OPENSSL
151         STREAM_SSL_OPTION_HANDLERS
152
153         case OPT_BOOTSTRAP_CA_CERT:
154             stream_ssl_set_ca_cert_file(optarg, true);
155             break;
156 #endif
157
158         case '?':
159             exit(EXIT_FAILURE);
160
161         case 0:
162             /* getopt_long() already set the value for us. */
163             break;
164
165         default:
166             abort();
167         }
168     }
169     free(short_options);
170 }
171
172 static void
173 usage(void)
174 {
175     printf("%s: Open vSwitch database JSON-RPC client\n"
176            "usage: %s [OPTIONS] COMMAND [ARG...]\n"
177            "\nValid commands are:\n"
178            "\n  list-dbs SERVER\n"
179            "    list databases available on SERVER\n"
180            "\n  get-schema SERVER DATABASE\n"
181            "    retrieve schema for DATABASE from SERVER\n"
182            "\n  list-tables SERVER DATABASE\n"
183            "    list tables for DATABASE on SERVER\n"
184            "\n  list-columns SERVER DATABASE [TABLE]\n"
185            "    list columns in TABLE (or all tables) in DATABASE on SERVER\n"
186            "\n  transact SERVER TRANSACTION\n"
187            "    run TRANSACTION (a JSON array of operations) on SERVER\n"
188            "    and print the results as JSON on stdout\n"
189            "\n  monitor SERVER DATABASE TABLE [COLUMN,...]...\n"
190            "    monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
191            "    COLUMNs may include !initial, !insert, !delete, !modify\n"
192            "    to avoid seeing the specified kinds of changes.\n"
193            "\n  dump SERVER DATABASE\n"
194            "    dump contents of DATABASE on SERVER to stdout\n",
195            program_name, program_name);
196     stream_usage("SERVER", true, true, true);
197     printf("\nOutput formatting options:\n"
198            "  -f, --format=FORMAT         set output formatting to FORMAT\n"
199            "                              (\"table\", \"html\", or \"csv\"\n"
200            "  --no-headings               omit table heading row\n"
201            "  --pretty                    pretty-print JSON in output");
202     daemon_usage();
203     vlog_usage();
204     printf("\nOther options:\n"
205            "  -h, --help                  display this help message\n"
206            "  -V, --version               display version information\n");
207     exit(EXIT_SUCCESS);
208 }
209 \f
210 static struct json *
211 parse_json(const char *s)
212 {
213     struct json *json = json_from_string(s);
214     if (json->type == JSON_STRING) {
215         ovs_fatal(0, "\"%s\": %s", s, json->u.string);
216     }
217     return json;
218 }
219
220 static struct jsonrpc *
221 open_jsonrpc(const char *server)
222 {
223     struct stream *stream;
224     int error;
225
226     error = stream_open_block(jsonrpc_stream_open(server, &stream), &stream);
227     if (error == EAFNOSUPPORT) {
228         struct pstream *pstream;
229
230         error = jsonrpc_pstream_open(server, &pstream);
231         if (error) {
232             ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
233         }
234
235         VLOG_INFO("%s: waiting for connection...", server);
236         error = pstream_accept_block(pstream, &stream);
237         if (error) {
238             ovs_fatal(error, "failed to accept connection on \"%s\"", server);
239         }
240
241         pstream_close(pstream);
242     } else if (error) {
243         ovs_fatal(error, "failed to connect to \"%s\"", server);
244     }
245
246     return jsonrpc_open(stream);
247 }
248
249 static void
250 print_json(struct json *json)
251 {
252     char *string = json_to_string(json, json_flags);
253     fputs(string, stdout);
254     free(string);
255 }
256
257 static void
258 print_and_free_json(struct json *json)
259 {
260     print_json(json);
261     json_destroy(json);
262 }
263
264 static void
265 check_ovsdb_error(struct ovsdb_error *error)
266 {
267     if (error) {
268         ovs_fatal(0, "%s", ovsdb_error_to_string(error));
269     }
270 }
271
272 static struct ovsdb_schema *
273 fetch_schema_from_rpc(struct jsonrpc *rpc, const char *database)
274 {
275     struct jsonrpc_msg *request, *reply;
276     struct ovsdb_schema *schema;
277     int error;
278
279     request = jsonrpc_create_request("get_schema",
280                                      json_array_create_1(
281                                          json_string_create(database)),
282                                      NULL);
283     error = jsonrpc_transact_block(rpc, request, &reply);
284     if (error) {
285         ovs_fatal(error, "transaction failed");
286     }
287     check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
288     jsonrpc_msg_destroy(reply);
289
290     return schema;
291 }
292
293 static struct ovsdb_schema *
294 fetch_schema(const char *server, const char *database)
295 {
296     struct ovsdb_schema *schema;
297     struct jsonrpc *rpc;
298
299     rpc = open_jsonrpc(server);
300     schema = fetch_schema_from_rpc(rpc, database);
301     jsonrpc_close(rpc);
302
303     return schema;
304 }
305 \f
306 struct column {
307     char *heading;
308     int width;
309 };
310
311 struct table {
312     char **cells;
313     struct column *columns;
314     size_t n_columns, allocated_columns;
315     size_t n_rows, allocated_rows;
316     size_t current_column;
317     char *caption;
318 };
319
320 static void
321 table_init(struct table *table)
322 {
323     memset(table, 0, sizeof *table);
324 }
325
326 static void
327 table_destroy(struct table *table)
328 {
329     size_t i;
330
331     for (i = 0; i < table->n_columns; i++) {
332         free(table->columns[i].heading);
333     }
334     free(table->columns);
335
336     for (i = 0; i < table->n_columns * table->n_rows; i++) {
337         free(table->cells[i]);
338     }
339     free(table->cells);
340
341     free(table->caption);
342 }
343
344 static void
345 table_set_caption(struct table *table, char *caption)
346 {
347     free(table->caption);
348     table->caption = caption;
349 }
350
351 static void
352 table_add_column(struct table *table, const char *heading, ...)
353     PRINTF_FORMAT(2, 3);
354
355 static void
356 table_add_column(struct table *table, const char *heading, ...)
357 {
358     struct column *column;
359     va_list args;
360
361     assert(!table->n_rows);
362     if (table->n_columns >= table->allocated_columns) {
363         table->columns = x2nrealloc(table->columns, &table->allocated_columns,
364                                     sizeof *table->columns);
365     }
366     column = &table->columns[table->n_columns++];
367
368     va_start(args, heading);
369     column->heading = xvasprintf(heading, args);
370     column->width = strlen(column->heading);
371     va_end(args);
372 }
373
374 static char **
375 table_cell__(const struct table *table, size_t row, size_t column)
376 {
377     return &table->cells[column + row * table->n_columns];
378 }
379
380 static void
381 table_add_row(struct table *table)
382 {
383     size_t x, y;
384
385     if (table->n_rows >= table->allocated_rows) {
386         table->cells = x2nrealloc(table->cells, &table->allocated_rows,
387                                   table->n_columns * sizeof *table->cells);
388     }
389
390     y = table->n_rows++;
391     table->current_column = 0;
392     for (x = 0; x < table->n_columns; x++) {
393         *table_cell__(table, y, x) = NULL;
394     }
395 }
396
397 static void
398 table_add_cell_nocopy(struct table *table, char *s)
399 {
400     size_t x, y;
401     int length;
402
403     assert(table->n_rows > 0);
404     assert(table->current_column < table->n_columns);
405
406     x = table->current_column++;
407     y = table->n_rows - 1;
408     *table_cell__(table, y, x) = s;
409
410     length = strlen(s);
411     if (length > table->columns[x].width) {
412         table->columns[x].width = length;
413     }
414 }
415
416 static void
417 table_add_cell(struct table *table, const char *format, ...)
418 {
419     va_list args;
420
421     va_start(args, format);
422     table_add_cell_nocopy(table, xvasprintf(format, args));
423     va_end(args);
424 }
425
426 static void
427 table_print_table_line__(struct ds *line)
428 {
429     puts(ds_cstr(line));
430     ds_clear(line);
431 }
432
433 static void
434 table_print_table__(const struct table *table)
435 {
436     static int n = 0;
437     struct ds line = DS_EMPTY_INITIALIZER;
438     size_t x, y;
439
440     if (n++ > 0) {
441         putchar('\n');
442     }
443
444     if (table->caption) {
445         puts(table->caption);
446     }
447
448     if (output_headings) {
449         for (x = 0; x < table->n_columns; x++) {
450             const struct column *column = &table->columns[x];
451             if (x) {
452                 ds_put_char(&line, ' ');
453             }
454             ds_put_format(&line, "%-*s", column->width, column->heading);
455         }
456         table_print_table_line__(&line);
457
458         for (x = 0; x < table->n_columns; x++) {
459             const struct column *column = &table->columns[x];
460             int i;
461
462             if (x) {
463                 ds_put_char(&line, ' ');
464             }
465             for (i = 0; i < column->width; i++) {
466                 ds_put_char(&line, '-');
467             }
468         }
469         table_print_table_line__(&line);
470     }
471
472     for (y = 0; y < table->n_rows; y++) {
473         for (x = 0; x < table->n_columns; x++) {
474             const char *cell = *table_cell__(table, y, x);
475             if (x) {
476                 ds_put_char(&line, ' ');
477             }
478             ds_put_format(&line, "%-*s", table->columns[x].width, cell);
479         }
480         table_print_table_line__(&line);
481     }
482
483     ds_destroy(&line);
484 }
485
486 static void
487 table_escape_html_text__(const char *s, size_t n)
488 {
489     size_t i;
490
491     for (i = 0; i < n; i++) {
492         char c = s[i];
493
494         switch (c) {
495         case '&':
496             fputs("&amp;", stdout);
497             break;
498         case '<':
499             fputs("&lt;", stdout);
500             break;
501         case '>':
502             fputs("&gt;", stdout);
503             break;
504         case '"':
505             fputs("&quot;", stdout);
506             break;
507         default:
508             putchar(c);
509             break;
510         }
511     }
512 }
513
514 static void
515 table_print_html_cell__(const char *element, const char *content)
516 {
517     const char *p;
518
519     printf("    <%s>", element);
520     for (p = content; *p; ) {
521         struct uuid uuid;
522
523         if (uuid_from_string_prefix(&uuid, p)) {
524             printf("<a href=\"#%.*s\">%.*s</a>", UUID_LEN, p, 8, p);
525             p += UUID_LEN;
526         } else {
527             table_escape_html_text__(p, 1);
528             p++;
529         }
530     }
531     printf("</%s>\n", element);
532 }
533
534 static void
535 table_print_html__(const struct table *table)
536 {
537     size_t x, y;
538
539     fputs("<table border=1>\n", stdout);
540
541     if (table->caption) {
542         table_print_html_cell__("caption", table->caption);
543     }
544
545     if (output_headings) {
546         fputs("  <tr>\n", stdout);
547         for (x = 0; x < table->n_columns; x++) {
548             const struct column *column = &table->columns[x];
549             table_print_html_cell__("th", column->heading);
550         }
551         fputs("  </tr>\n", stdout);
552     }
553
554     for (y = 0; y < table->n_rows; y++) {
555         fputs("  <tr>\n", stdout);
556         for (x = 0; x < table->n_columns; x++) {
557             const char *content = *table_cell__(table, y, x);
558
559             if (!strcmp(table->columns[x].heading, "_uuid")) {
560                 fputs("    <td><a name=\"", stdout);
561                 table_escape_html_text__(content, strlen(content));
562                 fputs("\">", stdout);
563                 table_escape_html_text__(content, 8);
564                 fputs("</a></td>\n", stdout);
565             } else {
566                 table_print_html_cell__("td", content);
567             }
568         }
569         fputs("  </tr>\n", stdout);
570     }
571
572     fputs("</table>\n", stdout);
573 }
574
575 static void
576 table_print_csv_cell__(const char *content)
577 {
578     const char *p;
579
580     if (!strpbrk(content, "\n\",")) {
581         fputs(content, stdout);
582     } else {
583         putchar('"');
584         for (p = content; *p != '\0'; p++) {
585             switch (*p) {
586             case '"':
587                 fputs("\"\"", stdout);
588                 break;
589             default:
590                 putchar(*p);
591                 break;
592             }
593         }
594         putchar('"');
595     }
596 }
597
598 static void
599 table_print_csv__(const struct table *table)
600 {
601     static int n = 0;
602     size_t x, y;
603
604     if (n++ > 0) {
605         putchar('\n');
606     }
607
608     if (table->caption) {
609         puts(table->caption);
610     }
611
612     if (output_headings) {
613         for (x = 0; x < table->n_columns; x++) {
614             const struct column *column = &table->columns[x];
615             if (x) {
616                 putchar(',');
617             }
618             table_print_csv_cell__(column->heading);
619         }
620         putchar('\n');
621     }
622
623     for (y = 0; y < table->n_rows; y++) {
624         for (x = 0; x < table->n_columns; x++) {
625             if (x) {
626                 putchar(',');
627             }
628             table_print_csv_cell__(*table_cell__(table, y, x));
629         }
630         putchar('\n');
631     }
632 }
633
634 static void
635 table_print(const struct table *table)
636 {
637     switch (output_format) {
638     case FMT_TABLE:
639         table_print_table__(table);
640         break;
641
642     case FMT_HTML:
643         table_print_html__(table);
644         break;
645
646     case FMT_CSV:
647         table_print_csv__(table);
648         break;
649     }
650 }
651 \f
652 static void
653 do_list_dbs(int argc OVS_UNUSED, char *argv[])
654 {
655     struct jsonrpc_msg *request, *reply;
656     struct jsonrpc *rpc;
657     int error;
658     size_t i;
659
660     rpc = open_jsonrpc(argv[1]);
661     request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
662                                      NULL);
663     error = jsonrpc_transact_block(rpc, request, &reply);
664     if (error) {
665         ovs_fatal(error, "transaction failed");
666     }
667
668     if (reply->result->type != JSON_ARRAY) {
669         ovs_fatal(0, "list_dbs response is not array");
670     }
671
672     for (i = 0; i < reply->result->u.array.n; i++) {
673         const struct json *name = reply->result->u.array.elems[i];
674
675         if (name->type != JSON_STRING) {
676             ovs_fatal(0, "list_dbs response %zu is not string", i);
677         }
678         puts(name->u.string);
679     }
680     jsonrpc_msg_destroy(reply);
681 }
682
683 static void
684 do_get_schema(int argc OVS_UNUSED, char *argv[])
685 {
686     struct ovsdb_schema *schema = fetch_schema(argv[1], argv[2]);
687     print_and_free_json(ovsdb_schema_to_json(schema));
688     ovsdb_schema_destroy(schema);
689 }
690
691 static void
692 do_list_tables(int argc OVS_UNUSED, char *argv[])
693 {
694     struct ovsdb_schema *schema;
695     struct shash_node *node;
696     struct table t;
697
698     schema = fetch_schema(argv[1], argv[2]);
699     table_init(&t);
700     table_add_column(&t, "Table");
701     SHASH_FOR_EACH (node, &schema->tables) {
702         struct ovsdb_table_schema *ts = node->data;
703
704         table_add_row(&t);
705         table_add_cell(&t, ts->name);
706     }
707     ovsdb_schema_destroy(schema);
708     table_print(&t);
709 }
710
711 static void
712 do_list_columns(int argc OVS_UNUSED, char *argv[])
713 {
714     const char *table_name = argv[3];
715     struct ovsdb_schema *schema;
716     struct shash_node *table_node;
717     struct table t;
718
719     schema = fetch_schema(argv[1], argv[2]);
720     table_init(&t);
721     if (!table_name) {
722         table_add_column(&t, "Table");
723     }
724     table_add_column(&t, "Column");
725     table_add_column(&t, "Type");
726     SHASH_FOR_EACH (table_node, &schema->tables) {
727         struct ovsdb_table_schema *ts = table_node->data;
728
729         if (!table_name || !strcmp(table_name, ts->name)) {
730             struct shash_node *column_node;
731
732             SHASH_FOR_EACH (column_node, &ts->columns) {
733                 const struct ovsdb_column *column = column_node->data;
734                 struct json *type = ovsdb_type_to_json(&column->type);
735
736                 table_add_row(&t);
737                 if (!table_name) {
738                     table_add_cell(&t, ts->name);
739                 }
740                 table_add_cell(&t, column->name);
741                 table_add_cell_nocopy(&t, json_to_string(type, JSSF_SORT));
742
743                 json_destroy(type);
744             }
745         }
746     }
747     ovsdb_schema_destroy(schema);
748     table_print(&t);
749 }
750
751 static void
752 do_transact(int argc OVS_UNUSED, char *argv[])
753 {
754     struct jsonrpc_msg *request, *reply;
755     struct json *transaction;
756     struct jsonrpc *rpc;
757     int error;
758
759     transaction = parse_json(argv[2]);
760
761     rpc = open_jsonrpc(argv[1]);
762     request = jsonrpc_create_request("transact", transaction, NULL);
763     error = jsonrpc_transact_block(rpc, request, &reply);
764     if (error) {
765         ovs_fatal(error, "transaction failed");
766     }
767     if (reply->error) {
768         ovs_fatal(error, "transaction returned error: %s",
769                   json_to_string(reply->error, json_flags));
770     }
771     print_json(reply->result);
772     putchar('\n');
773     jsonrpc_msg_destroy(reply);
774     jsonrpc_close(rpc);
775 }
776
777 static char *
778 format_json(const struct json *json, const struct ovsdb_type *type)
779 {
780     if (data_format == DF_JSON) {
781         return json_to_string(json, JSSF_SORT);
782     } else if (data_format == DF_STRING) {
783         struct ovsdb_datum datum;
784         struct ovsdb_error *error;
785         struct ds s;
786
787         error = ovsdb_datum_from_json(&datum, type, json, NULL);
788         if (error) {
789             return json_to_string(json, JSSF_SORT);
790         }
791
792         ds_init(&s);
793         ovsdb_datum_to_string(&datum, type, &s);
794         ovsdb_datum_destroy(&datum, type);
795         return ds_steal_cstr(&s);
796     } else {
797         NOT_REACHED();
798     }
799 }
800
801 static void
802 monitor_print_row(struct json *row, const char *type, const char *uuid,
803                   const struct ovsdb_column_set *columns, struct table *t)
804 {
805     size_t i;
806
807     if (!row) {
808         ovs_error(0, "missing %s row", type);
809         return;
810     } else if (row->type != JSON_OBJECT) {
811         ovs_error(0, "<row> is not object");
812         return;
813     }
814
815     table_add_row(t);
816     table_add_cell(t, uuid);
817     table_add_cell(t, type);
818     for (i = 0; i < columns->n_columns; i++) {
819         const struct ovsdb_column *column = columns->columns[i];
820         struct json *value = shash_find_data(json_object(row), column->name);
821         if (value) {
822             table_add_cell_nocopy(t, format_json(value, &column->type));
823         } else {
824             table_add_cell(t, "");
825         }
826     }
827 }
828
829 static void
830 monitor_print(struct json *table_updates,
831               const struct ovsdb_table_schema *table,
832               const struct ovsdb_column_set *columns, bool initial)
833 {
834     struct json *table_update;
835     struct shash_node *node;
836     struct table t;
837     size_t i;
838
839     table_init(&t);
840
841     if (table_updates->type != JSON_OBJECT) {
842         ovs_error(0, "<table-updates> is not object");
843         return;
844     }
845     table_update = shash_find_data(json_object(table_updates), table->name);
846     if (!table_update) {
847         return;
848     }
849     if (table_update->type != JSON_OBJECT) {
850         ovs_error(0, "<table-update> is not object");
851         return;
852     }
853
854     table_add_column(&t, "row");
855     table_add_column(&t, "action");
856     for (i = 0; i < columns->n_columns; i++) {
857         table_add_column(&t, "%s", columns->columns[i]->name);
858     }
859     SHASH_FOR_EACH (node, json_object(table_update)) {
860         struct json *row_update = node->data;
861         struct json *old, *new;
862
863         if (row_update->type != JSON_OBJECT) {
864             ovs_error(0, "<row-update> is not object");
865             continue;
866         }
867         old = shash_find_data(json_object(row_update), "old");
868         new = shash_find_data(json_object(row_update), "new");
869         if (initial) {
870             monitor_print_row(new, "initial", node->name, columns, &t);
871         } else if (!old) {
872             monitor_print_row(new, "insert", node->name, columns, &t);
873         } else if (!new) {
874             monitor_print_row(old, "delete", node->name, columns, &t);
875         } else {
876             monitor_print_row(old, "old", node->name, columns, &t);
877             monitor_print_row(new, "new", "", columns, &t);
878         }
879     }
880     table_print(&t);
881     table_destroy(&t);
882 }
883
884 static void
885 add_column(const char *server, const struct ovsdb_column *column,
886            struct ovsdb_column_set *columns, struct json *columns_json)
887 {
888     if (ovsdb_column_set_contains(columns, column->index)) {
889         ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
890                   server, column->name);
891     }
892     ovsdb_column_set_add(columns, column);
893     json_array_add(columns_json, json_string_create(column->name));
894 }
895
896 static struct json *
897 parse_monitor_columns(char *arg, const char *server, const char *database,
898                       const struct ovsdb_table_schema *table,
899                       struct ovsdb_column_set *columns)
900 {
901     bool initial, insert, delete, modify;
902     struct json *mr, *columns_json;
903     char *save_ptr = NULL;
904     char *token;
905
906     mr = json_object_create();
907     columns_json = json_array_create_empty();
908     json_object_put(mr, "columns", columns_json);
909
910     initial = insert = delete = modify = true;
911     for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
912          token = strtok_r(NULL, ",", &save_ptr)) {
913         if (!strcmp(token, "!initial")) {
914             initial = false;
915         } else if (!strcmp(token, "!insert")) {
916             insert = false;
917         } else if (!strcmp(token, "!delete")) {
918             delete = false;
919         } else if (!strcmp(token, "!modify")) {
920             modify = false;
921         } else {
922             const struct ovsdb_column *column;
923
924             column = ovsdb_table_schema_get_column(table, token);
925             if (!column) {
926                 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
927                           "column named \"%s\"",
928                           server, table->name, database, token);
929             }
930             add_column(server, column, columns, columns_json);
931         }
932     }
933
934     if (columns_json->u.array.n == 0) {
935         const struct shash_node **nodes;
936         size_t i, n;
937
938         n = shash_count(&table->columns);
939         nodes = shash_sort(&table->columns);
940         for (i = 0; i < n; i++) {
941             const struct ovsdb_column *column = nodes[i]->data;
942             if (column->index != OVSDB_COL_UUID
943                 && column->index != OVSDB_COL_VERSION) {
944                 add_column(server, column, columns, columns_json);
945             }
946         }
947         free(nodes);
948
949         add_column(server, ovsdb_table_schema_get_column(table,"_version"),
950                    columns, columns_json);
951     }
952
953     if (!initial || !insert || !delete || !modify) {
954         struct json *select = json_object_create();
955         json_object_put(select, "initial", json_boolean_create(initial));
956         json_object_put(select, "insert", json_boolean_create(insert));
957         json_object_put(select, "delete", json_boolean_create(delete));
958         json_object_put(select, "modify", json_boolean_create(modify));
959         json_object_put(mr, "select", select);
960     }
961
962     return mr;
963 }
964
965 static void
966 do_monitor(int argc, char *argv[])
967 {
968     const char *server = argv[1];
969     const char *database = argv[2];
970     const char *table_name = argv[3];
971     struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
972     struct ovsdb_table_schema *table;
973     struct ovsdb_schema *schema;
974     struct jsonrpc_msg *request;
975     struct jsonrpc *rpc;
976     struct json *monitor, *monitor_request_array,
977         *monitor_requests, *request_id;
978
979     rpc = open_jsonrpc(server);
980
981     schema = fetch_schema_from_rpc(rpc, database);
982     table = shash_find_data(&schema->tables, table_name);
983     if (!table) {
984         ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
985                   server, database, table_name);
986     }
987
988     monitor_request_array = json_array_create_empty();
989     if (argc > 4) {
990         int i;
991
992         for (i = 4; i < argc; i++) {
993             json_array_add(
994                 monitor_request_array,
995                 parse_monitor_columns(argv[i], server, database, table,
996                                       &columns));
997         }
998     } else {
999         /* Allocate a writable empty string since parse_monitor_columns() is
1000          * going to strtok() it and that's risky with literal "". */
1001         char empty[] = "";
1002         json_array_add(
1003             monitor_request_array,
1004             parse_monitor_columns(empty, server, database, table, &columns));
1005     }
1006
1007     monitor_requests = json_object_create();
1008     json_object_put(monitor_requests, table_name, monitor_request_array);
1009
1010     monitor = json_array_create_3(json_string_create(database),
1011                                   json_null_create(), monitor_requests);
1012     request = jsonrpc_create_request("monitor", monitor, NULL);
1013     request_id = json_clone(request->id);
1014     jsonrpc_send(rpc, request);
1015     for (;;) {
1016         struct jsonrpc_msg *msg;
1017         int error;
1018
1019         error = jsonrpc_recv_block(rpc, &msg);
1020         if (error) {
1021             ovsdb_schema_destroy(schema);
1022             ovs_fatal(error, "%s: receive failed", server);
1023         }
1024
1025         if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1026             jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1027                                                    msg->id));
1028         } else if (msg->type == JSONRPC_REPLY
1029                    && json_equal(msg->id, request_id)) {
1030             monitor_print(msg->result, table, &columns, true);
1031             fflush(stdout);
1032             if (get_detach()) {
1033                 /* daemonize() closes the standard file descriptors.  We output
1034                  * to stdout, so we need to save and restore STDOUT_FILENO. */
1035                 int fd = dup(STDOUT_FILENO);
1036                 daemonize();
1037                 dup2(fd, STDOUT_FILENO);
1038                 close(fd);
1039             }
1040         } else if (msg->type == JSONRPC_NOTIFY
1041                    && !strcmp(msg->method, "update")) {
1042             struct json *params = msg->params;
1043             if (params->type == JSON_ARRAY
1044                 && params->u.array.n == 2
1045                 && params->u.array.elems[0]->type == JSON_NULL) {
1046                 monitor_print(params->u.array.elems[1],
1047                               table, &columns, false);
1048                 fflush(stdout);
1049             }
1050         }
1051         jsonrpc_msg_destroy(msg);
1052     }
1053 }
1054
1055 struct dump_table_aux {
1056     struct ovsdb_datum **data;
1057     const struct ovsdb_column **columns;
1058     size_t n_columns;
1059 };
1060
1061 static int
1062 compare_data(size_t a_y, size_t b_y, size_t x,
1063              const struct dump_table_aux *aux)
1064 {
1065     return ovsdb_datum_compare_3way(&aux->data[a_y][x],
1066                                     &aux->data[b_y][x],
1067                                     &aux->columns[x]->type);
1068 }
1069
1070 static int
1071 compare_rows(size_t a_y, size_t b_y, void *aux_)
1072 {
1073     struct dump_table_aux *aux = aux_;
1074     size_t x;
1075
1076     /* Skip UUID columns on the first pass, since their values tend to be
1077      * random and make our results less reproducible. */
1078     for (x = 0; x < aux->n_columns; x++) {
1079         if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
1080             int cmp = compare_data(a_y, b_y, x, aux);
1081             if (cmp) {
1082                 return cmp;
1083             }
1084         }
1085     }
1086
1087     /* Use UUID columns as tie-breakers. */
1088     for (x = 0; x < aux->n_columns; x++) {
1089         if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
1090             int cmp = compare_data(a_y, b_y, x, aux);
1091             if (cmp) {
1092                 return cmp;
1093             }
1094         }
1095     }
1096
1097     return 0;
1098 }
1099
1100 static void
1101 swap_rows(size_t a_y, size_t b_y, void *aux_)
1102 {
1103     struct dump_table_aux *aux = aux_;
1104     struct ovsdb_datum *tmp = aux->data[a_y];
1105     aux->data[a_y] = aux->data[b_y];
1106     aux->data[b_y] = tmp;
1107 }
1108
1109 static char *
1110 format_data(const struct ovsdb_datum *datum, const struct ovsdb_type *type)
1111 {
1112     if (data_format == DF_JSON) {
1113         struct json *json = ovsdb_datum_to_json(datum, type);
1114         char *s = json_to_string(json, JSSF_SORT);
1115         json_destroy(json);
1116         return s;
1117     } else if (data_format == DF_STRING) {
1118         struct ds s;
1119
1120         ds_init(&s);
1121         ovsdb_datum_to_string(datum, type, &s);
1122         return ds_steal_cstr(&s);
1123     } else {
1124         NOT_REACHED();
1125     }
1126 }
1127
1128 static int
1129 compare_columns(const void *a_, const void *b_)
1130 {
1131     const struct ovsdb_column *const *ap = a_;
1132     const struct ovsdb_column *const *bp = b_;
1133     const struct ovsdb_column *a = *ap;
1134     const struct ovsdb_column *b = *bp;
1135
1136     return strcmp(a->name, b->name);
1137 }
1138
1139 static void
1140 dump_table(const struct ovsdb_table_schema *ts, struct json_array *rows)
1141 {
1142     const struct ovsdb_column **columns;
1143     size_t n_columns;
1144
1145     struct ovsdb_datum **data;
1146
1147     struct dump_table_aux aux;
1148     struct shash_node *node;
1149     struct table t;
1150     size_t x, y;
1151
1152     /* Sort columns by name, for reproducibility. */
1153     columns = xmalloc(shash_count(&ts->columns) * sizeof *columns);
1154     n_columns = 0;
1155     SHASH_FOR_EACH (node, &ts->columns) {
1156         struct ovsdb_column *column = node->data;
1157         if (strcmp(column->name, "_version")) {
1158             columns[n_columns++] = column;
1159         }
1160     }
1161     qsort(columns, n_columns, sizeof *columns, compare_columns);
1162
1163     /* Extract data from table. */
1164     data = xmalloc(rows->n * sizeof *data);
1165     for (y = 0; y < rows->n; y++) {
1166         struct shash *row;
1167
1168         if (rows->elems[y]->type != JSON_OBJECT) {
1169             ovs_fatal(0,  "row %zu in table %s response is not a JSON object: "
1170                       "%s", y, ts->name, json_to_string(rows->elems[y], 0));
1171         }
1172         row = json_object(rows->elems[y]);
1173
1174         data[y] = xmalloc(n_columns * sizeof **data);
1175         for (x = 0; x < n_columns; x++) {
1176             const struct json *json = shash_find_data(row, columns[x]->name);
1177             if (!json) {
1178                 ovs_fatal(0, "row %zu in table %s response lacks %s column",
1179                           y, ts->name, columns[x]->name);
1180             }
1181
1182             check_ovsdb_error(ovsdb_datum_from_json(&data[y][x],
1183                                                     &columns[x]->type,
1184                                                     json, NULL));
1185         }
1186     }
1187
1188     /* Sort rows by column values, for reproducibility. */
1189     aux.data = data;
1190     aux.columns = columns;
1191     aux.n_columns = n_columns;
1192     sort(rows->n, compare_rows, swap_rows, &aux);
1193
1194     /* Add column headings. */
1195     table_init(&t);
1196     table_set_caption(&t, xasprintf("%s table", ts->name));
1197     for (x = 0; x < n_columns; x++) {
1198         table_add_column(&t, "%s", columns[x]->name);
1199     }
1200
1201     /* Print rows. */
1202     for (y = 0; y < rows->n; y++) {
1203         table_add_row(&t);
1204         for (x = 0; x < n_columns; x++) {
1205             table_add_cell_nocopy(&t, format_data(&data[y][x],
1206                                                   &columns[x]->type));
1207         }
1208     }
1209     table_print(&t);
1210     table_destroy(&t);
1211 }
1212
1213 static void
1214 do_dump(int argc OVS_UNUSED, char *argv[])
1215 {
1216     const char *server = argv[1];
1217     const char *database = argv[2];
1218
1219     struct jsonrpc_msg *request, *reply;
1220     struct ovsdb_schema *schema;
1221     struct json *transaction;
1222     struct jsonrpc *rpc;
1223     int error;
1224
1225     const struct shash_node **tables;
1226     size_t n_tables;
1227
1228     size_t i;
1229
1230     rpc = open_jsonrpc(server);
1231
1232     schema = fetch_schema_from_rpc(rpc, database);
1233     tables = shash_sort(&schema->tables);
1234     n_tables = shash_count(&schema->tables);
1235
1236     /* Construct transaction to retrieve entire database. */
1237     transaction = json_array_create_1(json_string_create(database));
1238     for (i = 0; i < n_tables; i++) {
1239         const struct ovsdb_table_schema *ts = tables[i]->data;
1240         struct json *op, *columns;
1241         struct shash_node *node;
1242
1243         columns = json_array_create_empty();
1244         SHASH_FOR_EACH (node, &ts->columns) {
1245             const struct ovsdb_column *column = node->data;
1246
1247             if (strcmp(column->name, "_version")) {
1248                 json_array_add(columns, json_string_create(column->name));
1249             }
1250         }
1251
1252         op = json_object_create();
1253         json_object_put_string(op, "op", "select");
1254         json_object_put_string(op, "table", tables[i]->name);
1255         json_object_put(op, "where", json_array_create_empty());
1256         json_object_put(op, "columns", columns);
1257         json_array_add(transaction, op);
1258     }
1259
1260     /* Send request, get reply. */
1261     request = jsonrpc_create_request("transact", transaction, NULL);
1262     error = jsonrpc_transact_block(rpc, request, &reply);
1263     if (error) {
1264         ovs_fatal(error, "transaction failed");
1265     }
1266
1267     /* Print database contents. */
1268     if (reply->result->type != JSON_ARRAY
1269         || reply->result->u.array.n != n_tables) {
1270         ovs_fatal(0, "reply is not array of %zu elements: %s",
1271                   n_tables, json_to_string(reply->result, 0));
1272     }
1273     for (i = 0; i < n_tables; i++) {
1274         const struct ovsdb_table_schema *ts = tables[i]->data;
1275         const struct json *op_result = reply->result->u.array.elems[i];
1276         struct json *rows;
1277
1278         if (op_result->type != JSON_OBJECT
1279             || !(rows = shash_find_data(json_object(op_result), "rows"))
1280             || rows->type != JSON_ARRAY) {
1281             ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1282                       "member array: %s",
1283                       ts->name, json_to_string(op_result, 0));
1284         }
1285
1286         dump_table(ts, &rows->u.array);
1287     }
1288 }
1289
1290 static void
1291 do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1292 {
1293     usage();
1294 }
1295
1296 static const struct command all_commands[] = {
1297     { "list-dbs", 1, 1, do_list_dbs },
1298     { "get-schema", 2, 2, do_get_schema },
1299     { "list-tables", 2, 2, do_list_tables },
1300     { "list-columns", 2, 3, do_list_columns },
1301     { "transact", 2, 2, do_transact },
1302     { "monitor", 3, INT_MAX, do_monitor },
1303     { "dump", 2, 2, do_dump },
1304     { "help", 0, INT_MAX, do_help },
1305     { NULL, 0, 0, NULL },
1306 };