]> git.proxmox.com Git - mirror_ovs.git/blob - ovsdb/ovsdb-client.c
Merge "master" into "next".
[mirror_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-error.h"
37 #include "stream.h"
38 #include "stream-ssl.h"
39 #include "table.h"
40 #include "timeval.h"
41 #include "util.h"
42
43 #include "vlog.h"
44 #define THIS_MODULE VLM_ovsdb_client
45
46 /* --format: Output formatting. */
47 static enum {
48 FMT_TABLE, /* Textual table. */
49 FMT_HTML, /* HTML table. */
50 FMT_CSV /* Comma-separated lines. */
51 } output_format;
52
53 /* --wide: For --format=table, the maximum output width. */
54 static int output_width;
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 static const struct command all_commands[];
63
64 static void usage(void) NO_RETURN;
65 static void parse_options(int argc, char *argv[]);
66
67 int
68 main(int argc, char *argv[])
69 {
70 proctitle_init(argc, argv);
71 set_program_name(argv[0]);
72 time_init();
73 vlog_init();
74 parse_options(argc, argv);
75 signal(SIGPIPE, SIG_IGN);
76 run_command(argc - optind, argv + optind, all_commands);
77 return 0;
78 }
79
80 static void
81 parse_options(int argc, char *argv[])
82 {
83 enum {
84 OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1
85 };
86 static struct option long_options[] = {
87 {"wide", no_argument, &output_width, INT_MAX},
88 {"format", required_argument, 0, 'f'},
89 {"no-headings", no_argument, &output_headings, 0},
90 {"pretty", no_argument, &json_flags, JSSF_PRETTY | JSSF_SORT},
91 {"verbose", optional_argument, 0, 'v'},
92 {"help", no_argument, 0, 'h'},
93 {"version", no_argument, 0, 'V'},
94 DAEMON_LONG_OPTIONS,
95 #ifdef HAVE_OPENSSL
96 {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
97 STREAM_SSL_LONG_OPTIONS
98 #endif
99 {0, 0, 0, 0},
100 };
101 char *short_options = long_options_to_short_options(long_options);
102
103 output_width = isatty(fileno(stdout)) ? 79 : INT_MAX;
104 for (;;) {
105 int c;
106
107 c = getopt_long(argc, argv, short_options, long_options, NULL);
108 if (c == -1) {
109 break;
110 }
111
112 switch (c) {
113 case 'f':
114 if (!strcmp(optarg, "table")) {
115 output_format = FMT_TABLE;
116 } else if (!strcmp(optarg, "html")) {
117 output_format = FMT_HTML;
118 } else if (!strcmp(optarg, "csv")) {
119 output_format = FMT_CSV;
120 } else {
121 ovs_fatal(0, "unknown output format \"%s\"", optarg);
122 }
123 break;
124
125 case 'w':
126 output_width = INT_MAX;
127 break;
128
129 case 'h':
130 usage();
131
132 case 'V':
133 OVS_PRINT_VERSION(0, 0);
134 exit(EXIT_SUCCESS);
135
136 case 'v':
137 vlog_set_verbosity(optarg);
138 break;
139
140 DAEMON_OPTION_HANDLERS
141
142 #ifdef HAVE_OPENSSL
143 STREAM_SSL_OPTION_HANDLERS
144
145 case OPT_BOOTSTRAP_CA_CERT:
146 stream_ssl_set_ca_cert_file(optarg, true);
147 break;
148 #endif
149
150 case '?':
151 exit(EXIT_FAILURE);
152
153 case 0:
154 /* getopt_long() already set the value for us. */
155 break;
156
157 default:
158 abort();
159 }
160 }
161 free(short_options);
162 }
163
164 static void
165 usage(void)
166 {
167 printf("%s: Open vSwitch database JSON-RPC client\n"
168 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
169 "\nValid commands are:\n"
170 "\n list-dbs SERVER\n"
171 " list databases available on SERVER\n"
172 "\n get-schema SERVER DATABASE\n"
173 " retrieve schema for DATABASE from SERVER\n"
174 "\n list-tables SERVER DATABSE\n"
175 " list tables for DATABSAE on SERVER\n"
176 "\n list-columns SERVER DATABASE [TABLE]\n"
177 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
178 "\n transact SERVER TRANSACTION\n"
179 " run TRANSACTION (a JSON array of operations) on SERVER\n"
180 " and print the results as JSON on stdout\n"
181 "\n monitor SERVER DATABASE TABLE [COLUMN,...] [SELECT,...]\n"
182 " monitor contents of (COLUMNs in) TABLE in DATABASE on SERVER\n"
183 " Valid SELECTs are: initial, insert, delete, modify\n",
184 program_name, program_name);
185 stream_usage("SERVER", true, true, true);
186 printf("\nOutput formatting options:\n"
187 " -f, --format=FORMAT set output formatting to FORMAT\n"
188 " (\"table\", \"html\", or \"csv\"\n"
189 " --wide don't limit TTY lines to 79 bytes\n"
190 " --no-headings omit table heading row\n"
191 " --pretty pretty-print JSON in output");
192 daemon_usage();
193 vlog_usage();
194 printf("\nOther options:\n"
195 " -h, --help display this help message\n"
196 " -V, --version display version information\n");
197 exit(EXIT_SUCCESS);
198 }
199 \f
200 static struct json *
201 parse_json(const char *s)
202 {
203 struct json *json = json_from_string(s);
204 if (json->type == JSON_STRING) {
205 ovs_fatal(0, "\"%s\": %s", s, json->u.string);
206 }
207 return json;
208 }
209
210 static struct jsonrpc *
211 open_jsonrpc(const char *server)
212 {
213 struct stream *stream;
214 int error;
215
216 error = stream_open_block(server, &stream);
217 if (error == EAFNOSUPPORT) {
218 struct pstream *pstream;
219
220 error = pstream_open(server, &pstream);
221 if (error) {
222 ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
223 }
224
225 VLOG_INFO("%s: waiting for connection...", server);
226 error = pstream_accept_block(pstream, &stream);
227 if (error) {
228 ovs_fatal(error, "failed to accept connection on \"%s\"", server);
229 }
230
231 pstream_close(pstream);
232 } else if (error) {
233 ovs_fatal(error, "failed to connect to \"%s\"", server);
234 }
235
236 return jsonrpc_open(stream);
237 }
238
239 static void
240 print_json(struct json *json)
241 {
242 char *string = json_to_string(json, json_flags);
243 fputs(string, stdout);
244 free(string);
245 }
246
247 static void
248 print_and_free_json(struct json *json)
249 {
250 print_json(json);
251 json_destroy(json);
252 }
253
254 static void
255 check_ovsdb_error(struct ovsdb_error *error)
256 {
257 if (error) {
258 ovs_fatal(0, "%s", ovsdb_error_to_string(error));
259 }
260 }
261
262 static struct ovsdb_schema *
263 fetch_schema_from_rpc(struct jsonrpc *rpc, const char *database)
264 {
265 struct jsonrpc_msg *request, *reply;
266 struct ovsdb_schema *schema;
267 int error;
268
269 request = jsonrpc_create_request("get_schema",
270 json_array_create_1(
271 json_string_create(database)),
272 NULL);
273 error = jsonrpc_transact_block(rpc, request, &reply);
274 if (error) {
275 ovs_fatal(error, "transaction failed");
276 }
277 check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
278 jsonrpc_msg_destroy(reply);
279
280 return schema;
281 }
282
283 static struct ovsdb_schema *
284 fetch_schema(const char *server, const char *database)
285 {
286 struct ovsdb_schema *schema;
287 struct jsonrpc *rpc;
288
289 rpc = open_jsonrpc(server);
290 schema = fetch_schema_from_rpc(rpc, database);
291 jsonrpc_close(rpc);
292
293 return schema;
294 }
295 \f
296 struct column {
297 char *heading;
298 int width;
299 };
300
301 struct table {
302 char **cells;
303 struct column *columns;
304 size_t n_columns, allocated_columns;
305 size_t n_rows, allocated_rows;
306 size_t current_column;
307 };
308
309 static void
310 table_init(struct table *table)
311 {
312 memset(table, 0, sizeof *table);
313 }
314
315 static void
316 table_destroy(struct table *table)
317 {
318 size_t i;
319
320 for (i = 0; i < table->n_columns; i++) {
321 free(table->columns[i].heading);
322 }
323 free(table->columns);
324
325 for (i = 0; i < table->n_columns * table->n_rows; i++) {
326 free(table->cells[i]);
327 }
328 free(table->cells);
329 }
330
331 static void
332 table_add_column(struct table *table, const char *heading, ...)
333 PRINTF_FORMAT(2, 3);
334
335 static void
336 table_add_column(struct table *table, const char *heading, ...)
337 {
338 struct column *column;
339 va_list args;
340
341 assert(!table->n_rows);
342 if (table->n_columns >= table->allocated_columns) {
343 table->columns = x2nrealloc(table->columns, &table->allocated_columns,
344 sizeof *table->columns);
345 }
346 column = &table->columns[table->n_columns++];
347
348 va_start(args, heading);
349 column->heading = xvasprintf(heading, args);
350 column->width = strlen(column->heading);
351 va_end(args);
352 }
353
354 static char **
355 table_cell__(const struct table *table, size_t row, size_t column)
356 {
357 return &table->cells[column + row * table->n_columns];
358 }
359
360 static void
361 table_add_row(struct table *table)
362 {
363 size_t x, y;
364
365 if (table->n_rows >= table->allocated_rows) {
366 table->cells = x2nrealloc(table->cells, &table->allocated_rows,
367 table->n_columns * sizeof *table->cells);
368 }
369
370 y = table->n_rows++;
371 table->current_column = 0;
372 for (x = 0; x < table->n_columns; x++) {
373 *table_cell__(table, y, x) = NULL;
374 }
375 }
376
377 static void
378 table_add_cell_nocopy(struct table *table, char *s)
379 {
380 size_t x, y;
381 int length;
382
383 assert(table->n_rows > 0);
384 assert(table->current_column < table->n_columns);
385
386 x = table->current_column++;
387 y = table->n_rows - 1;
388 *table_cell__(table, y, x) = s;
389
390 length = strlen(s);
391 if (length > table->columns[x].width) {
392 table->columns[x].width = length;
393 }
394 }
395
396 static void
397 table_add_cell(struct table *table, const char *format, ...)
398 {
399 va_list args;
400
401 va_start(args, format);
402 table_add_cell_nocopy(table, xvasprintf(format, args));
403 va_end(args);
404 }
405
406 static void
407 table_print_table_line__(struct ds *line, size_t max_width)
408 {
409 ds_truncate(line, max_width);
410 puts(ds_cstr(line));
411 ds_clear(line);
412 }
413
414 static void
415 table_print_table__(const struct table *table)
416 {
417 struct ds line = DS_EMPTY_INITIALIZER;
418 size_t x, y;
419
420 if (output_headings) {
421 for (x = 0; x < table->n_columns; x++) {
422 const struct column *column = &table->columns[x];
423 if (x) {
424 ds_put_char(&line, ' ');
425 }
426 ds_put_format(&line, "%-*s", column->width, column->heading);
427 }
428 table_print_table_line__(&line, output_width);
429
430 for (x = 0; x < table->n_columns; x++) {
431 const struct column *column = &table->columns[x];
432 int i;
433
434 if (x) {
435 ds_put_char(&line, ' ');
436 }
437 for (i = 0; i < column->width; i++) {
438 ds_put_char(&line, '-');
439 }
440 }
441 table_print_table_line__(&line, output_width);
442 }
443
444 for (y = 0; y < table->n_rows; y++) {
445 for (x = 0; x < table->n_columns; x++) {
446 const char *cell = *table_cell__(table, y, x);
447 if (x) {
448 ds_put_char(&line, ' ');
449 }
450 ds_put_format(&line, "%-*s", table->columns[x].width, cell);
451 }
452 table_print_table_line__(&line, output_width);
453 }
454
455 ds_destroy(&line);
456 }
457
458 static void
459 table_print_html_cell__(const char *element, const char *content)
460 {
461 const char *p;
462
463 printf(" <%s>", element);
464 for (p = content; *p != '\0'; p++) {
465 switch (*p) {
466 case '&':
467 fputs("&amp;", stdout);
468 break;
469 case '<':
470 fputs("&lt;", stdout);
471 break;
472 case '>':
473 fputs("&gt;", stdout);
474 break;
475 default:
476 putchar(*p);
477 break;
478 }
479 }
480 printf("</%s>\n", element);
481 }
482
483 static void
484 table_print_html__(const struct table *table)
485 {
486 size_t x, y;
487
488 fputs("<table>\n", stdout);
489
490 if (output_headings) {
491 fputs(" <tr>\n", stdout);
492 for (x = 0; x < table->n_columns; x++) {
493 const struct column *column = &table->columns[x];
494 table_print_html_cell__("th", column->heading);
495 }
496 fputs(" </tr>\n", stdout);
497 }
498
499 for (y = 0; y < table->n_rows; y++) {
500 fputs(" <tr>\n", stdout);
501 for (x = 0; x < table->n_columns; x++) {
502 table_print_html_cell__("td", *table_cell__(table, y, x));
503 }
504 fputs(" </tr>\n", stdout);
505 }
506
507 fputs("</table>\n", stdout);
508 }
509
510 static void
511 table_print_csv_cell__(const char *content)
512 {
513 const char *p;
514
515 if (!strpbrk(content, "\n\",")) {
516 fputs(content, stdout);
517 } else {
518 putchar('"');
519 for (p = content; *p != '\0'; p++) {
520 switch (*p) {
521 case '"':
522 fputs("\"\"", stdout);
523 break;
524 default:
525 putchar(*p);
526 break;
527 }
528 }
529 putchar('"');
530 }
531 }
532
533 static void
534 table_print_csv__(const struct table *table)
535 {
536 size_t x, y;
537
538 if (output_headings) {
539 for (x = 0; x < table->n_columns; x++) {
540 const struct column *column = &table->columns[x];
541 if (x) {
542 putchar(',');
543 }
544 table_print_csv_cell__(column->heading);
545 }
546 putchar('\n');
547 }
548
549 for (y = 0; y < table->n_rows; y++) {
550 for (x = 0; x < table->n_columns; x++) {
551 if (x) {
552 putchar(',');
553 }
554 table_print_csv_cell__(*table_cell__(table, y, x));
555 }
556 putchar('\n');
557 }
558 }
559
560 static void
561 table_print(const struct table *table)
562 {
563 switch (output_format) {
564 case FMT_TABLE:
565 table_print_table__(table);
566 break;
567
568 case FMT_HTML:
569 table_print_html__(table);
570 break;
571
572 case FMT_CSV:
573 table_print_csv__(table);
574 break;
575 }
576 }
577 \f
578 static void
579 do_list_dbs(int argc OVS_UNUSED, char *argv[])
580 {
581 struct jsonrpc_msg *request, *reply;
582 struct jsonrpc *rpc;
583 int error;
584 size_t i;
585
586 rpc = open_jsonrpc(argv[1]);
587 request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
588 NULL);
589 error = jsonrpc_transact_block(rpc, request, &reply);
590 if (error) {
591 ovs_fatal(error, "transaction failed");
592 }
593
594 if (reply->result->type != JSON_ARRAY) {
595 ovs_fatal(0, "list_dbs response is not array");
596 }
597
598 for (i = 0; i < reply->result->u.array.n; i++) {
599 const struct json *name = reply->result->u.array.elems[i];
600
601 if (name->type != JSON_STRING) {
602 ovs_fatal(0, "list_dbs response %zu is not string", i);
603 }
604 puts(name->u.string);
605 }
606 jsonrpc_msg_destroy(reply);
607 }
608
609 static void
610 do_get_schema(int argc OVS_UNUSED, char *argv[])
611 {
612 struct ovsdb_schema *schema = fetch_schema(argv[1], argv[2]);
613 print_and_free_json(ovsdb_schema_to_json(schema));
614 ovsdb_schema_destroy(schema);
615 }
616
617 static void
618 do_list_tables(int argc OVS_UNUSED, char *argv[])
619 {
620 struct ovsdb_schema *schema;
621 struct shash_node *node;
622 struct table t;
623
624 schema = fetch_schema(argv[1], argv[2]);
625 table_init(&t);
626 table_add_column(&t, "Table");
627 table_add_column(&t, "Comment");
628 SHASH_FOR_EACH (node, &schema->tables) {
629 struct ovsdb_table_schema *ts = node->data;
630
631 table_add_row(&t);
632 table_add_cell(&t, ts->name);
633 if (ts->comment) {
634 table_add_cell(&t, ts->comment);
635 }
636 }
637 ovsdb_schema_destroy(schema);
638 table_print(&t);
639 }
640
641 static void
642 do_list_columns(int argc OVS_UNUSED, char *argv[])
643 {
644 const char *table_name = argv[3];
645 struct ovsdb_schema *schema;
646 struct shash_node *table_node;
647 struct table t;
648
649 schema = fetch_schema(argv[1], argv[2]);
650 table_init(&t);
651 if (!table_name) {
652 table_add_column(&t, "Table");
653 }
654 table_add_column(&t, "Column");
655 table_add_column(&t, "Type");
656 table_add_column(&t, "Comment");
657 SHASH_FOR_EACH (table_node, &schema->tables) {
658 struct ovsdb_table_schema *ts = table_node->data;
659
660 if (!table_name || !strcmp(table_name, ts->name)) {
661 struct shash_node *column_node;
662
663 SHASH_FOR_EACH (column_node, &ts->columns) {
664 const struct ovsdb_column *column = column_node->data;
665 struct json *type = ovsdb_type_to_json(&column->type);
666
667 table_add_row(&t);
668 if (!table_name) {
669 table_add_cell(&t, ts->name);
670 }
671 table_add_cell(&t, column->name);
672 table_add_cell_nocopy(&t, json_to_string(type, JSSF_SORT));
673 if (column->comment) {
674 table_add_cell(&t, column->comment);
675 }
676
677 json_destroy(type);
678 }
679 }
680 }
681 ovsdb_schema_destroy(schema);
682 table_print(&t);
683 }
684
685 static void
686 do_transact(int argc OVS_UNUSED, char *argv[])
687 {
688 struct jsonrpc_msg *request, *reply;
689 struct json *transaction;
690 struct jsonrpc *rpc;
691 int error;
692
693 transaction = parse_json(argv[2]);
694
695 rpc = open_jsonrpc(argv[1]);
696 request = jsonrpc_create_request("transact", transaction, NULL);
697 error = jsonrpc_transact_block(rpc, request, &reply);
698 if (error) {
699 ovs_fatal(error, "transaction failed");
700 }
701 if (reply->error) {
702 ovs_fatal(error, "transaction returned error: %s",
703 json_to_string(reply->error, json_flags));
704 }
705 print_json(reply->result);
706 putchar('\n');
707 jsonrpc_msg_destroy(reply);
708 jsonrpc_close(rpc);
709 }
710
711 static void
712 monitor_print_row(struct json *row, const char *type, const char *uuid,
713 const struct ovsdb_column_set *columns, struct table *t)
714 {
715 size_t i;
716
717 if (!row) {
718 ovs_error(0, "missing %s row", type);
719 return;
720 } else if (row->type != JSON_OBJECT) {
721 ovs_error(0, "<row> is not object");
722 return;
723 }
724
725 table_add_row(t);
726 table_add_cell(t, uuid);
727 table_add_cell(t, type);
728 for (i = 0; i < columns->n_columns; i++) {
729 const struct ovsdb_column *column = columns->columns[i];
730 struct json *value = shash_find_data(json_object(row), column->name);
731 if (value) {
732 table_add_cell_nocopy(t, json_to_string(value, JSSF_SORT));
733 } else {
734 table_add_cell(t, "");
735 }
736 }
737 }
738
739 static void
740 monitor_print(struct json *table_updates,
741 const struct ovsdb_table_schema *table,
742 const struct ovsdb_column_set *columns, bool initial)
743 {
744 struct json *table_update;
745 struct shash_node *node;
746 struct table t;
747 size_t i;
748
749 table_init(&t);
750
751 if (table_updates->type != JSON_OBJECT) {
752 ovs_error(0, "<table-updates> is not object");
753 return;
754 }
755 table_update = shash_find_data(json_object(table_updates), table->name);
756 if (!table_update) {
757 return;
758 }
759 if (table_update->type != JSON_OBJECT) {
760 ovs_error(0, "<table-update> is not object");
761 return;
762 }
763
764 table_add_column(&t, "row");
765 table_add_column(&t, "action");
766 for (i = 0; i < columns->n_columns; i++) {
767 table_add_column(&t, "%s", columns->columns[i]->name);
768 }
769 SHASH_FOR_EACH (node, json_object(table_update)) {
770 struct json *row_update = node->data;
771 struct json *old, *new;
772
773 if (row_update->type != JSON_OBJECT) {
774 ovs_error(0, "<row-update> is not object");
775 continue;
776 }
777 old = shash_find_data(json_object(row_update), "old");
778 new = shash_find_data(json_object(row_update), "new");
779 if (initial) {
780 monitor_print_row(new, "initial", node->name, columns, &t);
781 } else if (!old) {
782 monitor_print_row(new, "insert", node->name, columns, &t);
783 } else if (!new) {
784 monitor_print_row(old, "delete", node->name, columns, &t);
785 } else {
786 monitor_print_row(old, "old", node->name, columns, &t);
787 monitor_print_row(new, "new", "", columns, &t);
788 }
789 }
790 table_print(&t);
791 table_destroy(&t);
792 }
793
794 static void
795 do_monitor(int argc, char *argv[])
796 {
797 const char *server = argv[1];
798 const char *database = argv[2];
799 const char *table_name = argv[3];
800 struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
801 struct ovsdb_table_schema *table;
802 struct ovsdb_schema *schema;
803 struct jsonrpc_msg *request;
804 struct jsonrpc *rpc;
805 struct json *select, *monitor, *monitor_request, *monitor_requests,
806 *request_id;
807
808 rpc = open_jsonrpc(server);
809
810 schema = fetch_schema_from_rpc(rpc, database);
811 table = shash_find_data(&schema->tables, table_name);
812 if (!table) {
813 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
814 server, database, table_name);
815 }
816
817 if (argc >= 5 && *argv[4] != '\0') {
818 char *save_ptr = NULL;
819 char *token;
820
821 for (token = strtok_r(argv[4], ",", &save_ptr); token != NULL;
822 token = strtok_r(NULL, ",", &save_ptr)) {
823 const struct ovsdb_column *column;
824 column = ovsdb_table_schema_get_column(table, token);
825 if (!column) {
826 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
827 "column named \"%s\"",
828 server, table_name, database, token);
829 }
830 ovsdb_column_set_add(&columns, column);
831 }
832 } else {
833 struct shash_node *node;
834
835 SHASH_FOR_EACH (node, &table->columns) {
836 const struct ovsdb_column *column = node->data;
837 if (column->index != OVSDB_COL_UUID) {
838 ovsdb_column_set_add(&columns, column);
839 }
840 }
841 }
842
843 if (argc >= 6 && *argv[5] != '\0') {
844 char *save_ptr = NULL;
845 char *token;
846
847 select = json_object_create();
848 for (token = strtok_r(argv[5], ",", &save_ptr); token != NULL;
849 token = strtok_r(NULL, ",", &save_ptr)) {
850 json_object_put(select, token, json_boolean_create(true));
851 }
852 } else {
853 select = NULL;
854 }
855
856 monitor_request = json_object_create();
857 json_object_put(monitor_request,
858 "columns", ovsdb_column_set_to_json(&columns));
859 if (select) {
860 json_object_put(monitor_request, "select", select);
861 }
862
863 monitor_requests = json_object_create();
864 json_object_put(monitor_requests, table_name, monitor_request);
865
866 monitor = json_array_create_3(json_string_create(database),
867 json_null_create(), monitor_requests);
868 request = jsonrpc_create_request("monitor", monitor, NULL);
869 request_id = json_clone(request->id);
870 jsonrpc_send(rpc, request);
871 for (;;) {
872 struct jsonrpc_msg *msg;
873 int error;
874
875 error = jsonrpc_recv_block(rpc, &msg);
876 if (error) {
877 ovsdb_schema_destroy(schema);
878 ovs_fatal(error, "%s: receive failed", server);
879 }
880
881 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
882 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
883 msg->id));
884 } else if (msg->type == JSONRPC_REPLY
885 && json_equal(msg->id, request_id)) {
886 monitor_print(msg->result, table, &columns, true);
887 fflush(stdout);
888 if (get_detach()) {
889 /* daemonize() closes the standard file descriptors. We output
890 * to stdout, so we need to save and restore STDOUT_FILENO. */
891 int fd = dup(STDOUT_FILENO);
892 daemonize();
893 dup2(fd, STDOUT_FILENO);
894 close(fd);
895 }
896 } else if (msg->type == JSONRPC_NOTIFY
897 && !strcmp(msg->method, "update")) {
898 struct json *params = msg->params;
899 if (params->type == JSON_ARRAY
900 && params->u.array.n == 2
901 && params->u.array.elems[0]->type == JSON_NULL) {
902 monitor_print(params->u.array.elems[1],
903 table, &columns, false);
904 fflush(stdout);
905 }
906 }
907 jsonrpc_msg_destroy(msg);
908 }
909 }
910
911 static void
912 do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
913 {
914 usage();
915 }
916
917 static const struct command all_commands[] = {
918 { "list-dbs", 1, 1, do_list_dbs },
919 { "get-schema", 2, 2, do_get_schema },
920 { "list-tables", 2, 2, do_list_tables },
921 { "list-columns", 2, 3, do_list_columns },
922 { "transact", 2, 2, do_transact },
923 { "monitor", 3, 5, do_monitor },
924 { "help", 0, INT_MAX, do_help },
925 { NULL, 0, 0, NULL },
926 };