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