]> git.proxmox.com Git - ovs.git/blob - ovsdb/ovsdb-client.c
ovsdb-client: Fix memory leaks
[ovs.git] / ovsdb / ovsdb-client.c
1 /*
2 * Copyright (c) 2009-2017 Nicira, Inc.
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 <ctype.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 "dirs.h"
33 #include "openvswitch/dynamic-string.h"
34 #include "fatal-signal.h"
35 #include "file.h"
36 #include "openvswitch/json.h"
37 #include "jsonrpc.h"
38 #include "lib/table.h"
39 #include "log.h"
40 #include "ovsdb.h"
41 #include "ovsdb-data.h"
42 #include "ovsdb-error.h"
43 #include "openvswitch/poll-loop.h"
44 #include "row.h"
45 #include "sort.h"
46 #include "svec.h"
47 #include "stream.h"
48 #include "stream-ssl.h"
49 #include "table.h"
50 #include "monitor.h"
51 #include "condition.h"
52 #include "timeval.h"
53 #include "unixctl.h"
54 #include "util.h"
55 #include "openvswitch/vlog.h"
56
57 VLOG_DEFINE_THIS_MODULE(ovsdb_client);
58
59 enum args_needed {
60 NEED_NONE, /* No JSON-RPC connection or database name needed. */
61 NEED_RPC, /* JSON-RPC connection needed. */
62 NEED_DATABASE /* JSON-RPC connection and database name needed. */
63 };
64
65 struct ovsdb_client_command {
66 const char *name;
67 enum args_needed need;
68 int min_args;
69 int max_args;
70 void (*handler)(struct jsonrpc *rpc, const char *database,
71 int argc, char *argv[]);
72 };
73
74 /* --timestamp: Print a timestamp before each update on "monitor" command? */
75 static bool timestamp;
76
77 /* --force: Ignore schema differences for "restore" command? */
78 static bool force;
79
80 /* Format for table output. */
81 static struct table_style table_style = TABLE_STYLE_DEFAULT;
82
83 static const struct ovsdb_client_command *get_all_commands(void);
84
85 OVS_NO_RETURN static void usage(void);
86 static void parse_options(int argc, char *argv[]);
87 static struct jsonrpc *open_jsonrpc(const char *server);
88 static void fetch_dbs(struct jsonrpc *, struct svec *dbs);
89
90 int
91 main(int argc, char *argv[])
92 {
93 const struct ovsdb_client_command *command;
94 char *database;
95 struct jsonrpc *rpc;
96
97 ovs_cmdl_proctitle_init(argc, argv);
98 set_program_name(argv[0]);
99 service_start(&argc, &argv);
100 parse_options(argc, argv);
101 fatal_ignore_sigpipe();
102
103 daemon_become_new_user(false);
104 if (optind >= argc) {
105 ovs_fatal(0, "missing command name; use --help for help");
106 }
107
108 for (command = get_all_commands(); ; command++) {
109 if (!command->name) {
110 VLOG_FATAL("unknown command '%s'; use --help for help",
111 argv[optind]);
112 } else if (!strcmp(command->name, argv[optind])) {
113 break;
114 }
115 }
116 optind++;
117
118 if (command->need != NEED_NONE) {
119 if (argc - optind > command->min_args
120 && (isalpha((unsigned char) argv[optind][0])
121 && strchr(argv[optind], ':'))) {
122 rpc = open_jsonrpc(argv[optind++]);
123 } else {
124 char *sock = xasprintf("unix:%s/db.sock", ovs_rundir());
125 rpc = open_jsonrpc(sock);
126 free(sock);
127 }
128 } else {
129 rpc = NULL;
130 }
131
132 if (command->need == NEED_DATABASE) {
133 struct svec dbs;
134
135 svec_init(&dbs);
136 fetch_dbs(rpc, &dbs);
137 if (argc - optind > command->min_args
138 && svec_contains(&dbs, argv[optind])) {
139 database = xstrdup(argv[optind++]);
140 } else if (svec_contains(&dbs, "Open_vSwitch")) {
141 database = xstrdup("Open_vSwitch");
142 } else {
143 size_t n = 0;
144 const char *best = NULL;
145 for (size_t i = 0; i < dbs.n; i++) {
146 if (dbs.names[i][0] != '_') {
147 best = dbs.names[i];
148 n++;
149 }
150 }
151 if (n != 1) {
152 jsonrpc_close(rpc);
153 ovs_fatal(0, "no default database for `%s' command, please "
154 "specify a database name", command->name);
155 }
156 database = xstrdup(best);
157 }
158 svec_destroy(&dbs);
159 } else {
160 database = NULL;
161 }
162
163 if (argc - optind < command->min_args ||
164 argc - optind > command->max_args) {
165 free(database);
166 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
167 command->name);
168 }
169
170 command->handler(rpc, database, argc - optind, argv + optind);
171
172 free(database);
173 jsonrpc_close(rpc);
174
175 if (ferror(stdout)) {
176 VLOG_FATAL("write to stdout failed");
177 }
178 if (ferror(stderr)) {
179 VLOG_FATAL("write to stderr failed");
180 }
181
182 return 0;
183 }
184
185 static void
186 parse_options(int argc, char *argv[])
187 {
188 enum {
189 OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
190 OPT_TIMESTAMP,
191 OPT_FORCE,
192 VLOG_OPTION_ENUMS,
193 DAEMON_OPTION_ENUMS,
194 TABLE_OPTION_ENUMS,
195 SSL_OPTION_ENUMS,
196 };
197 static const struct option long_options[] = {
198 {"help", no_argument, NULL, 'h'},
199 {"version", no_argument, NULL, 'V'},
200 {"timestamp", no_argument, NULL, OPT_TIMESTAMP},
201 {"force", no_argument, NULL, OPT_FORCE},
202 VLOG_LONG_OPTIONS,
203 DAEMON_LONG_OPTIONS,
204 #ifdef HAVE_OPENSSL
205 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
206 STREAM_SSL_LONG_OPTIONS,
207 #endif
208 TABLE_LONG_OPTIONS,
209 {NULL, 0, NULL, 0},
210 };
211 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
212
213 table_style.format = TF_TABLE;
214
215 for (;;) {
216 int c;
217
218 c = getopt_long(argc, argv, short_options, long_options, NULL);
219 if (c == -1) {
220 break;
221 }
222
223 switch (c) {
224 case 'h':
225 usage();
226
227 case 'V':
228 ovs_print_version(0, 0);
229 exit(EXIT_SUCCESS);
230
231 VLOG_OPTION_HANDLERS
232 DAEMON_OPTION_HANDLERS
233 TABLE_OPTION_HANDLERS(&table_style)
234 STREAM_SSL_OPTION_HANDLERS
235
236 case OPT_BOOTSTRAP_CA_CERT:
237 stream_ssl_set_ca_cert_file(optarg, true);
238 break;
239
240 case OPT_TIMESTAMP:
241 timestamp = true;
242 break;
243
244 case OPT_FORCE:
245 force = true;
246 break;
247
248 case '?':
249 exit(EXIT_FAILURE);
250
251 case 0:
252 /* getopt_long() already set the value for us. */
253 break;
254
255 default:
256 abort();
257 }
258 }
259 free(short_options);
260 }
261
262 static void
263 usage(void)
264 {
265 printf("%s: Open vSwitch database JSON-RPC client\n"
266 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
267 "\nValid commands are:\n"
268 "\n list-dbs [SERVER]\n"
269 " list databases available on SERVER\n"
270 "\n get-schema [SERVER] [DATABASE]\n"
271 " retrieve schema for DATABASE from SERVER\n"
272 "\n get-schema-version [SERVER] [DATABASE]\n"
273 " retrieve schema for DATABASE from SERVER and report only its\n"
274 " version number on stdout\n"
275 "\n get-schema-cksum [SERVER] [DATABASE]\n"
276 " retrieve schema for DATABASE from SERVER and report only its\n"
277 " checksum on stdout\n"
278 "\n list-tables [SERVER] [DATABASE]\n"
279 " list tables for DATABASE on SERVER\n"
280 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
281 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
282 "\n transact [SERVER] TRANSACTION\n"
283 " run TRANSACTION (params for \"transact\" request) on SERVER\n"
284 " and print the results as JSON on stdout\n"
285 "\n query [SERVER] TRANSACTION\n"
286 " run TRANSACTION (params for \"transact\" request) on SERVER,\n"
287 " as read-only, and print the results as JSON on stdout\n"
288 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
289 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
290 " COLUMNs may include !initial, !insert, !delete, !modify\n"
291 " to avoid seeing the specified kinds of changes.\n"
292 "\n monitor-cond [SERVER] [DATABASE] CONDITION TABLE [COLUMN,...]...\n"
293 " monitor contents that match CONDITION of COLUMNs in TABLE in\n"
294 " DATABASE on SERVER.\n"
295 " COLUMNs may include !initial, !insert, !delete, !modify\n"
296 " to avoid seeing the specified kinds of changes.\n"
297 "\n monitor [SERVER] [DATABASE] ALL\n"
298 " monitor all changes to all columns in all tables\n"
299 " in DATBASE on SERVER.\n"
300 "\n dump [SERVER] [DATABASE]\n"
301 " dump contents of DATABASE on SERVER to stdout\n"
302 "\n backup [SERVER] [DATABASE] > SNAPSHOT\n"
303 " dump database contents in the form of a database file\n"
304 "\n [--force] restore [SERVER] [DATABASE] < SNAPSHOT\n"
305 " restore database contents from a database file\n"
306 "\n lock [SERVER] LOCK\n"
307 " create or wait for LOCK in SERVER\n"
308 "\n steal [SERVER] LOCK\n"
309 " steal LOCK from SERVER\n"
310 "\n unlock [SERVER] LOCK\n"
311 " unlock LOCK from SERVER\n"
312 "\nThe default SERVER is unix:%s/db.sock.\n"
313 "The default DATABASE is Open_vSwitch.\n",
314 program_name, program_name, ovs_rundir());
315 stream_usage("SERVER", true, true, true);
316 table_usage();
317 printf(" --timestamp timestamp \"monitor\" output");
318 daemon_usage();
319 vlog_usage();
320 printf("\nOther options:\n"
321 " -h, --help display this help message\n"
322 " -V, --version display version information\n");
323 exit(EXIT_SUCCESS);
324 }
325 \f
326 static void
327 check_txn(int error, struct jsonrpc_msg **reply_)
328 {
329 struct jsonrpc_msg *reply = *reply_;
330
331 if (error) {
332 ovs_fatal(error, "transaction failed");
333 }
334
335 if (reply->error) {
336 ovs_fatal(error, "transaction returned error: %s",
337 json_to_string(reply->error, table_style.json_flags));
338 }
339 }
340
341 static struct json *
342 parse_json(const char *s)
343 {
344 struct json *json = json_from_string(s);
345 if (json->type == JSON_STRING) {
346 ovs_fatal(0, "\"%s\": %s", s, json->u.string);
347 }
348 return json;
349 }
350
351 static struct jsonrpc *
352 open_jsonrpc(const char *server)
353 {
354 struct stream *stream;
355 int error;
356
357 error = stream_open_block(jsonrpc_stream_open(server, &stream,
358 DSCP_DEFAULT), &stream);
359 if (error == EAFNOSUPPORT) {
360 struct pstream *pstream;
361
362 error = jsonrpc_pstream_open(server, &pstream, DSCP_DEFAULT);
363 if (error) {
364 ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
365 }
366
367 VLOG_INFO("%s: waiting for connection...", server);
368 error = pstream_accept_block(pstream, &stream);
369 if (error) {
370 ovs_fatal(error, "failed to accept connection on \"%s\"", server);
371 }
372
373 pstream_close(pstream);
374 } else if (error) {
375 ovs_fatal(error, "failed to connect to \"%s\"", server);
376 }
377
378 return jsonrpc_open(stream);
379 }
380
381 static void
382 print_json(struct json *json)
383 {
384 char *string = json_to_string(json, table_style.json_flags);
385 puts(string);
386 free(string);
387 }
388
389 static void
390 print_and_free_json(struct json *json)
391 {
392 print_json(json);
393 json_destroy(json);
394 }
395
396 static void
397 check_ovsdb_error(struct ovsdb_error *error)
398 {
399 if (error) {
400 ovs_fatal(0, "%s", ovsdb_error_to_string(error));
401 }
402 }
403
404 static struct ovsdb_schema *
405 fetch_schema(struct jsonrpc *rpc, const char *database)
406 {
407 struct jsonrpc_msg *request, *reply;
408 struct ovsdb_schema *schema;
409
410 request = jsonrpc_create_request("get_schema",
411 json_array_create_1(
412 json_string_create(database)),
413 NULL);
414 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
415 check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
416 jsonrpc_msg_destroy(reply);
417
418 return schema;
419 }
420
421 static void
422 fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
423 {
424 struct jsonrpc_msg *request, *reply;
425 size_t i;
426
427 request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
428 NULL);
429
430 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
431 if (reply->result->type != JSON_ARRAY) {
432 ovs_fatal(0, "list_dbs response is not array");
433 }
434
435 for (i = 0; i < reply->result->u.array.n; i++) {
436 const struct json *name = reply->result->u.array.elems[i];
437
438 if (name->type != JSON_STRING) {
439 ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i);
440 }
441 svec_add(dbs, name->u.string);
442 }
443 jsonrpc_msg_destroy(reply);
444 svec_sort(dbs);
445 }
446 \f
447 static void
448 do_list_dbs(struct jsonrpc *rpc, const char *database OVS_UNUSED,
449 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
450 {
451 const char *db_name;
452 struct svec dbs;
453 size_t i;
454
455 svec_init(&dbs);
456 fetch_dbs(rpc, &dbs);
457 SVEC_FOR_EACH (i, db_name, &dbs) {
458 puts(db_name);
459 }
460 svec_destroy(&dbs);
461 }
462
463 static void
464 do_get_schema(struct jsonrpc *rpc, const char *database,
465 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
466 {
467 struct ovsdb_schema *schema = fetch_schema(rpc, database);
468 print_and_free_json(ovsdb_schema_to_json(schema));
469 ovsdb_schema_destroy(schema);
470 }
471
472 static void
473 do_get_schema_version(struct jsonrpc *rpc, const char *database,
474 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
475 {
476 struct ovsdb_schema *schema = fetch_schema(rpc, database);
477 puts(schema->version);
478 ovsdb_schema_destroy(schema);
479 }
480
481 static void
482 do_get_schema_cksum(struct jsonrpc *rpc, const char *database,
483 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
484 {
485 struct ovsdb_schema *schema = fetch_schema(rpc, database);
486 puts(schema->cksum);
487 ovsdb_schema_destroy(schema);
488 }
489
490 static void
491 do_list_tables(struct jsonrpc *rpc, const char *database,
492 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
493 {
494 struct ovsdb_schema *schema;
495 struct shash_node *node;
496 struct table t;
497
498 schema = fetch_schema(rpc, database);
499 table_init(&t);
500 table_add_column(&t, "Table");
501 SHASH_FOR_EACH (node, &schema->tables) {
502 struct ovsdb_table_schema *ts = node->data;
503
504 table_add_row(&t);
505 table_add_cell(&t)->text = xstrdup(ts->name);
506 }
507 ovsdb_schema_destroy(schema);
508 table_print(&t, &table_style);
509 table_destroy(&t);
510 }
511
512 static void
513 do_list_columns(struct jsonrpc *rpc, const char *database,
514 int argc OVS_UNUSED, char *argv[])
515 {
516 const char *table_name = argv[0];
517 struct ovsdb_schema *schema;
518 struct shash_node *table_node;
519 struct table t;
520
521 schema = fetch_schema(rpc, database);
522 table_init(&t);
523 if (!table_name) {
524 table_add_column(&t, "Table");
525 }
526 table_add_column(&t, "Column");
527 table_add_column(&t, "Type");
528 SHASH_FOR_EACH (table_node, &schema->tables) {
529 struct ovsdb_table_schema *ts = table_node->data;
530
531 if (!table_name || !strcmp(table_name, ts->name)) {
532 struct shash_node *column_node;
533
534 SHASH_FOR_EACH (column_node, &ts->columns) {
535 const struct ovsdb_column *column = column_node->data;
536
537 table_add_row(&t);
538 if (!table_name) {
539 table_add_cell(&t)->text = xstrdup(ts->name);
540 }
541 table_add_cell(&t)->text = xstrdup(column->name);
542 table_add_cell(&t)->json = ovsdb_type_to_json(&column->type);
543 }
544 }
545 }
546 ovsdb_schema_destroy(schema);
547 table_print(&t, &table_style);
548 table_destroy(&t);
549 }
550
551 static struct json *
552 do_transact__(struct jsonrpc *rpc, struct json *transaction)
553 {
554 struct jsonrpc_msg *request, *reply;
555
556 request = jsonrpc_create_request("transact", transaction, NULL);
557 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
558 struct json *result = json_clone(reply->result);
559 jsonrpc_msg_destroy(reply);
560
561 return result;
562 }
563
564 static void
565 do_transact(struct jsonrpc *rpc, const char *database OVS_UNUSED,
566 int argc OVS_UNUSED, char *argv[])
567 {
568 print_and_free_json(do_transact__(rpc, parse_json(argv[0])));
569 }
570
571 static void
572 do_query(struct jsonrpc *rpc, const char *database OVS_UNUSED,
573 int argc OVS_UNUSED, char *argv[])
574 {
575 struct json *transaction = parse_json(argv[0]);
576
577 if (transaction->type != JSON_ARRAY) {
578 ovs_fatal(0, "not a valid OVSDB query");
579 }
580
581 /* Append an "abort" operation to the query. */
582 struct json *abort_op = json_object_create();
583 json_object_put_string(abort_op, "op", "abort");
584 json_array_add(transaction, abort_op);
585 size_t abort_idx = transaction->u.array.n - 2;
586
587 /* Run query. */
588 struct json *result = do_transact__(rpc, transaction);
589
590 /* If the "abort" operation ended the transaction, remove its result. */
591 if (result->type == JSON_ARRAY
592 && result->u.array.n == abort_idx + 1
593 && result->u.array.elems[abort_idx]->type == JSON_OBJECT) {
594 struct json *op_result = result->u.array.elems[abort_idx];
595 struct json *error = shash_find_data(json_object(op_result), "error");
596 if (error
597 && error->type == JSON_STRING
598 && !strcmp(json_string(error), "aborted")) {
599 result->u.array.n--;
600 json_destroy(op_result);
601 }
602 }
603
604 /* Print the result. */
605 print_and_free_json(result);
606 }
607 \f
608 /* "monitor" command. */
609
610 struct monitored_table {
611 struct ovsdb_table_schema *table;
612 struct ovsdb_column_set columns;
613 };
614
615 static void
616 monitor_print_row(struct json *row, const char *type, const char *uuid,
617 const struct ovsdb_column_set *columns, struct table *t)
618 {
619 size_t i;
620
621 if (!row) {
622 ovs_error(0, "missing %s row", type);
623 return;
624 } else if (row->type != JSON_OBJECT) {
625 ovs_error(0, "<row> is not object");
626 return;
627 }
628
629 table_add_row(t);
630 table_add_cell(t)->text = xstrdup(uuid);
631 table_add_cell(t)->text = xstrdup(type);
632 for (i = 0; i < columns->n_columns; i++) {
633 const struct ovsdb_column *column = columns->columns[i];
634 struct json *value = shash_find_data(json_object(row), column->name);
635 struct cell *cell = table_add_cell(t);
636 if (value) {
637 cell->json = json_clone(value);
638 cell->type = &column->type;
639 }
640 }
641 }
642
643 static void
644 monitor_print_table(struct json *table_update,
645 const struct monitored_table *mt, char *caption,
646 bool initial)
647 {
648 const struct ovsdb_table_schema *table = mt->table;
649 const struct ovsdb_column_set *columns = &mt->columns;
650 struct shash_node *node;
651 struct table t;
652 size_t i;
653
654 if (table_update->type != JSON_OBJECT) {
655 ovs_error(0, "<table-update> for table %s is not object", table->name);
656 return;
657 }
658
659 table_init(&t);
660 table_set_timestamp(&t, timestamp);
661 table_set_caption(&t, caption);
662
663 table_add_column(&t, "row");
664 table_add_column(&t, "action");
665 for (i = 0; i < columns->n_columns; i++) {
666 table_add_column(&t, "%s", columns->columns[i]->name);
667 }
668 SHASH_FOR_EACH (node, json_object(table_update)) {
669 struct json *row_update = node->data;
670 struct json *old, *new;
671
672 if (row_update->type != JSON_OBJECT) {
673 ovs_error(0, "<row-update> is not object");
674 continue;
675 }
676 old = shash_find_data(json_object(row_update), "old");
677 new = shash_find_data(json_object(row_update), "new");
678 if (initial) {
679 monitor_print_row(new, "initial", node->name, columns, &t);
680 } else if (!old) {
681 monitor_print_row(new, "insert", node->name, columns, &t);
682 } else if (!new) {
683 monitor_print_row(old, "delete", node->name, columns, &t);
684 } else {
685 monitor_print_row(old, "old", node->name, columns, &t);
686 monitor_print_row(new, "new", "", columns, &t);
687 }
688 }
689 table_print(&t, &table_style);
690 table_destroy(&t);
691 }
692
693 static void
694 monitor_print(struct json *table_updates,
695 const struct monitored_table *mts, size_t n_mts,
696 bool initial)
697 {
698 size_t i;
699
700 if (table_updates->type != JSON_OBJECT) {
701 ovs_error(0, "<table-updates> is not object");
702 return;
703 }
704
705 for (i = 0; i < n_mts; i++) {
706 const struct monitored_table *mt = &mts[i];
707 struct json *table_update = shash_find_data(json_object(table_updates),
708 mt->table->name);
709 if (table_update) {
710 monitor_print_table(table_update, mt,
711 n_mts > 1 ? xstrdup(mt->table->name) : NULL,
712 initial);
713 }
714 }
715 }
716
717 static void
718 monitor2_print_row(struct json *row, const char *type, const char *uuid,
719 const struct ovsdb_column_set *columns, struct table *t)
720 {
721 if (!strcmp(type, "delete")) {
722 if (row->type != JSON_NULL) {
723 ovs_error(0, "delete method does not expect <row>");
724 return;
725 }
726
727 table_add_row(t);
728 table_add_cell(t)->text = xstrdup(uuid);
729 table_add_cell(t)->text = xstrdup(type);
730 } else {
731 if (!row || row->type != JSON_OBJECT) {
732 ovs_error(0, "<row> is not object");
733 return;
734 }
735 monitor_print_row(row, type, uuid, columns, t);
736 }
737 }
738
739 static void
740 monitor2_print_table(struct json *table_update2,
741 const struct monitored_table *mt, char *caption)
742 {
743 const struct ovsdb_table_schema *table = mt->table;
744 const struct ovsdb_column_set *columns = &mt->columns;
745 struct shash_node *node;
746 struct table t;
747
748 if (table_update2->type != JSON_OBJECT) {
749 ovs_error(0, "<table-update> for table %s is not object", table->name);
750 return;
751 }
752
753 table_init(&t);
754 table_set_timestamp(&t, timestamp);
755 table_set_caption(&t, caption);
756
757 table_add_column(&t, "row");
758 table_add_column(&t, "action");
759 for (size_t i = 0; i < columns->n_columns; i++) {
760 table_add_column(&t, "%s", columns->columns[i]->name);
761 }
762 SHASH_FOR_EACH (node, json_object(table_update2)) {
763 struct json *row_update2 = node->data;
764 const char *operation;
765 struct json *row;
766 const char *ops[] = {"delete", "initial", "modify", "insert"};
767
768 if (row_update2->type != JSON_OBJECT) {
769 ovs_error(0, "<row-update2> is not object");
770 continue;
771 }
772
773 /* row_update2 contains one of objects indexed by ops[] */
774 for (int i = 0; i < ARRAY_SIZE(ops); i++) {
775 operation = ops[i];
776 row = shash_find_data(json_object(row_update2), operation);
777
778 if (row) {
779 monitor2_print_row(row, operation, node->name, columns, &t);
780 break;
781 }
782 }
783 }
784 table_print(&t, &table_style);
785 table_destroy(&t);
786 }
787
788 static void
789 monitor2_print(struct json *table_updates2,
790 const struct monitored_table *mts, size_t n_mts)
791 {
792 size_t i;
793
794 if (table_updates2->type != JSON_OBJECT) {
795 ovs_error(0, "<table-updates2> is not object");
796 return;
797 }
798
799 for (i = 0; i < n_mts; i++) {
800 const struct monitored_table *mt = &mts[i];
801 struct json *table_update = shash_find_data(
802 json_object(table_updates2),
803 mt->table->name);
804 if (table_update) {
805 monitor2_print_table(table_update, mt,
806 n_mts > 1 ? xstrdup(mt->table->name) : NULL);
807 }
808 }
809 }
810
811 static void
812 add_column(const char *server, const struct ovsdb_column *column,
813 struct ovsdb_column_set *columns, struct json *columns_json)
814 {
815 if (ovsdb_column_set_contains(columns, column->index)) {
816 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
817 server, column->name);
818 }
819 ovsdb_column_set_add(columns, column);
820 json_array_add(columns_json, json_string_create(column->name));
821 }
822
823 static struct json *
824 parse_monitor_columns(char *arg, const char *server, const char *database,
825 const struct ovsdb_table_schema *table,
826 struct ovsdb_column_set *columns)
827 {
828 bool initial, insert, delete, modify;
829 struct json *mr, *columns_json;
830 char *save_ptr = NULL;
831 char *token;
832
833 mr = json_object_create();
834 columns_json = json_array_create_empty();
835 json_object_put(mr, "columns", columns_json);
836
837 initial = insert = delete = modify = true;
838 for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
839 token = strtok_r(NULL, ",", &save_ptr)) {
840 if (!strcmp(token, "!initial")) {
841 initial = false;
842 } else if (!strcmp(token, "!insert")) {
843 insert = false;
844 } else if (!strcmp(token, "!delete")) {
845 delete = false;
846 } else if (!strcmp(token, "!modify")) {
847 modify = false;
848 } else {
849 const struct ovsdb_column *column;
850
851 column = ovsdb_table_schema_get_column(table, token);
852 if (!column) {
853 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
854 "column named \"%s\"",
855 server, table->name, database, token);
856 }
857 add_column(server, column, columns, columns_json);
858 }
859 }
860
861 if (columns_json->u.array.n == 0) {
862 const struct shash_node **nodes;
863 size_t i, n;
864
865 n = shash_count(&table->columns);
866 nodes = shash_sort(&table->columns);
867 for (i = 0; i < n; i++) {
868 const struct ovsdb_column *column = nodes[i]->data;
869 if (column->index != OVSDB_COL_UUID
870 && column->index != OVSDB_COL_VERSION) {
871 add_column(server, column, columns, columns_json);
872 }
873 }
874 free(nodes);
875
876 add_column(server, ovsdb_table_schema_get_column(table, "_version"),
877 columns, columns_json);
878 }
879
880 if (!initial || !insert || !delete || !modify) {
881 struct json *select = json_object_create();
882 json_object_put(select, "initial", json_boolean_create(initial));
883 json_object_put(select, "insert", json_boolean_create(insert));
884 json_object_put(select, "delete", json_boolean_create(delete));
885 json_object_put(select, "modify", json_boolean_create(modify));
886 json_object_put(mr, "select", select);
887 }
888
889 return mr;
890 }
891
892 static void
893 ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
894 const char *argv[] OVS_UNUSED, void *exiting_)
895 {
896 bool *exiting = exiting_;
897 *exiting = true;
898 unixctl_command_reply(conn, NULL);
899 }
900
901 static void
902 ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
903 const char *argv[] OVS_UNUSED, void *blocked_)
904 {
905 bool *blocked = blocked_;
906
907 if (!*blocked) {
908 *blocked = true;
909 unixctl_command_reply(conn, NULL);
910 } else {
911 unixctl_command_reply(conn, "already blocking");
912 }
913 }
914
915 static void
916 ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
917 const char *argv[] OVS_UNUSED, void *blocked_)
918 {
919 bool *blocked = blocked_;
920
921 if (*blocked) {
922 *blocked = false;
923 unixctl_command_reply(conn, NULL);
924 } else {
925 unixctl_command_reply(conn, "already unblocked");
926 }
927 }
928
929 static void
930 ovsdb_client_cond_change(struct unixctl_conn *conn, int argc OVS_UNUSED,
931 const char *argv[], void *rpc_)
932 {
933 struct jsonrpc *rpc = rpc_;
934 struct json *monitor_cond_update_requests = json_object_create();
935 struct json *monitor_cond_update_request = json_object_create();
936 struct json *params;
937 struct jsonrpc_msg *request;
938
939 json_object_put(monitor_cond_update_request, "where",
940 json_from_string(argv[2]));
941 json_object_put(monitor_cond_update_requests,
942 argv[1],
943 json_array_create_1(monitor_cond_update_request));
944
945 params = json_array_create_3(json_null_create(),json_null_create(),
946 monitor_cond_update_requests);
947
948 request = jsonrpc_create_request("monitor_cond_change", params, NULL);
949 jsonrpc_send(rpc, request);
950
951 VLOG_DBG("cond change %s %s", argv[1], argv[2]);
952 unixctl_command_reply(conn, "condiiton changed");
953 }
954
955 static void
956 add_monitored_table(int argc, char *argv[],
957 const char *server, const char *database,
958 struct json *condition,
959 struct ovsdb_table_schema *table,
960 struct json *monitor_requests,
961 struct monitored_table **mts,
962 size_t *n_mts, size_t *allocated_mts)
963 {
964 struct json *monitor_request_array, *mr;
965 struct monitored_table *mt;
966
967 if (*n_mts >= *allocated_mts) {
968 *mts = x2nrealloc(*mts, allocated_mts, sizeof **mts);
969 }
970 mt = &(*mts)[(*n_mts)++];
971 mt->table = table;
972 ovsdb_column_set_init(&mt->columns);
973
974 monitor_request_array = json_array_create_empty();
975 if (argc > 1) {
976 int i;
977
978 for (i = 1; i < argc; i++) {
979 mr = parse_monitor_columns(argv[i], server, database, table,
980 &mt->columns);
981 if (i == 1 && condition) {
982 json_object_put(mr, "where", condition);
983 }
984 json_array_add(monitor_request_array, mr);
985 }
986 } else {
987 /* Allocate a writable empty string since parse_monitor_columns()
988 * is going to strtok() it and that's risky with literal "". */
989 char empty[] = "";
990
991 mr = parse_monitor_columns(empty, server, database,
992 table, &mt->columns);
993 if (condition) {
994 json_object_put(mr, "where", condition);
995 }
996 json_array_add(monitor_request_array, mr);
997 }
998
999 json_object_put(monitor_requests, table->name, monitor_request_array);
1000 }
1001
1002 static void
1003 destroy_monitored_table(struct monitored_table *mts, size_t n)
1004 {
1005 int i;
1006
1007 for (i = 0; i < n; i++) {
1008 struct monitored_table *mt = &mts[i];
1009 ovsdb_column_set_destroy(&mt->columns);
1010 }
1011
1012 free(mts);
1013 }
1014
1015 static void
1016 do_monitor__(struct jsonrpc *rpc, const char *database,
1017 enum ovsdb_monitor_version version,
1018 int argc, char *argv[], struct json *condition)
1019 {
1020 const char *server = jsonrpc_get_name(rpc);
1021 const char *table_name = argv[0];
1022 struct unixctl_server *unixctl;
1023 struct ovsdb_schema *schema;
1024 struct jsonrpc_msg *request;
1025 struct json *monitor, *monitor_requests, *request_id;
1026 bool exiting = false;
1027 bool blocked = false;
1028
1029 struct monitored_table *mts;
1030 size_t n_mts, allocated_mts;
1031
1032 ovs_assert(version < OVSDB_MONITOR_VERSION_MAX);
1033
1034 daemon_save_fd(STDOUT_FILENO);
1035 daemonize_start(false);
1036 if (get_detach()) {
1037 int error;
1038
1039 error = unixctl_server_create(NULL, &unixctl);
1040 if (error) {
1041 ovs_fatal(error, "failed to create unixctl server");
1042 }
1043
1044 unixctl_command_register("exit", "", 0, 0,
1045 ovsdb_client_exit, &exiting);
1046 unixctl_command_register("ovsdb-client/block", "", 0, 0,
1047 ovsdb_client_block, &blocked);
1048 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
1049 ovsdb_client_unblock, &blocked);
1050 unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
1051 ovsdb_client_cond_change, rpc);
1052 } else {
1053 unixctl = NULL;
1054 }
1055
1056 schema = fetch_schema(rpc, database);
1057
1058 monitor_requests = json_object_create();
1059
1060 mts = NULL;
1061 n_mts = allocated_mts = 0;
1062 if (strcmp(table_name, "ALL")) {
1063 struct ovsdb_table_schema *table;
1064
1065 table = shash_find_data(&schema->tables, table_name);
1066 if (!table) {
1067 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
1068 server, database, table_name);
1069 }
1070
1071 add_monitored_table(argc, argv, server, database, condition, table,
1072 monitor_requests, &mts, &n_mts, &allocated_mts);
1073 } else {
1074 size_t n = shash_count(&schema->tables);
1075 const struct shash_node **nodes = shash_sort(&schema->tables);
1076 size_t i;
1077
1078 if (condition) {
1079 ovs_fatal(0, "ALL tables are not allowed with condition");
1080 }
1081
1082 for (i = 0; i < n; i++) {
1083 struct ovsdb_table_schema *table = nodes[i]->data;
1084
1085 add_monitored_table(argc, argv, server, database, NULL, table,
1086 monitor_requests,
1087 &mts, &n_mts, &allocated_mts);
1088 }
1089 free(nodes);
1090 }
1091
1092 monitor = json_array_create_3(json_string_create(database),
1093 json_null_create(), monitor_requests);
1094 const char *method = version == OVSDB_MONITOR_V2 ? "monitor_cond"
1095 : "monitor";
1096
1097 request = jsonrpc_create_request(method, monitor, NULL);
1098 request_id = json_clone(request->id);
1099 jsonrpc_send(rpc, request);
1100
1101 for (;;) {
1102 unixctl_server_run(unixctl);
1103 while (!blocked) {
1104 struct jsonrpc_msg *msg;
1105 int error;
1106
1107 error = jsonrpc_recv(rpc, &msg);
1108 if (error == EAGAIN) {
1109 break;
1110 } else if (error) {
1111 ovs_fatal(error, "%s: receive failed", server);
1112 }
1113
1114 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1115 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1116 msg->id));
1117 } else if (msg->type == JSONRPC_REPLY
1118 && json_equal(msg->id, request_id)) {
1119 switch(version) {
1120 case OVSDB_MONITOR_V1:
1121 monitor_print(msg->result, mts, n_mts, true);
1122 break;
1123 case OVSDB_MONITOR_V2:
1124 monitor2_print(msg->result, mts, n_mts);
1125 break;
1126 case OVSDB_MONITOR_VERSION_MAX:
1127 default:
1128 OVS_NOT_REACHED();
1129 }
1130 fflush(stdout);
1131 daemonize_complete();
1132 } else if (msg->type == JSONRPC_NOTIFY
1133 && !strcmp(msg->method, "update")) {
1134 struct json *params = msg->params;
1135 if (params->type == JSON_ARRAY
1136 && params->u.array.n == 2
1137 && params->u.array.elems[0]->type == JSON_NULL) {
1138 monitor_print(params->u.array.elems[1], mts, n_mts, false);
1139 fflush(stdout);
1140 }
1141 } else if (msg->type == JSONRPC_NOTIFY
1142 && version == OVSDB_MONITOR_V2
1143 && !strcmp(msg->method, "update2")) {
1144 struct json *params = msg->params;
1145 if (params->type == JSON_ARRAY
1146 && params->u.array.n == 2
1147 && params->u.array.elems[0]->type == JSON_NULL) {
1148 monitor2_print(params->u.array.elems[1], mts, n_mts);
1149 fflush(stdout);
1150 }
1151 }
1152 jsonrpc_msg_destroy(msg);
1153 }
1154
1155 if (exiting) {
1156 break;
1157 }
1158
1159 jsonrpc_run(rpc);
1160 jsonrpc_wait(rpc);
1161 if (!blocked) {
1162 jsonrpc_recv_wait(rpc);
1163 }
1164 unixctl_server_wait(unixctl);
1165 poll_block();
1166 }
1167
1168 json_destroy(request_id);
1169 unixctl_server_destroy(unixctl);
1170 ovsdb_schema_destroy(schema);
1171 destroy_monitored_table(mts, n_mts);
1172 }
1173
1174 static void
1175 do_monitor(struct jsonrpc *rpc, const char *database,
1176 int argc, char *argv[])
1177 {
1178 do_monitor__(rpc, database, OVSDB_MONITOR_V1, argc, argv, NULL);
1179 }
1180
1181 static void
1182 do_monitor_cond(struct jsonrpc *rpc, const char *database,
1183 int argc, char *argv[])
1184 {
1185 struct ovsdb_condition cnd;
1186 struct json *condition = NULL;
1187 struct ovsdb_schema *schema;
1188 struct ovsdb_table_schema *table;
1189 const char *table_name = argv[1];
1190
1191 ovs_assert(argc > 1);
1192 schema = fetch_schema(rpc, database);
1193 table = shash_find_data(&schema->tables, table_name);
1194 if (!table) {
1195 ovs_fatal(0, "%s does not have a table named \"%s\"",
1196 database, table_name);
1197 }
1198 condition = parse_json(argv[0]);
1199 check_ovsdb_error(ovsdb_condition_from_json(table, condition,
1200 NULL, &cnd));
1201 ovsdb_condition_destroy(&cnd);
1202 do_monitor__(rpc, database, OVSDB_MONITOR_V2, --argc, ++argv, condition);
1203 ovsdb_schema_destroy(schema);
1204 }
1205
1206 struct dump_table_aux {
1207 struct ovsdb_datum **data;
1208 const struct ovsdb_column **columns;
1209 size_t n_columns;
1210 };
1211
1212 static int
1213 compare_data(size_t a_y, size_t b_y, size_t x,
1214 const struct dump_table_aux *aux)
1215 {
1216 return ovsdb_datum_compare_3way(&aux->data[a_y][x],
1217 &aux->data[b_y][x],
1218 &aux->columns[x]->type);
1219 }
1220
1221 static int
1222 compare_rows(size_t a_y, size_t b_y, void *aux_)
1223 {
1224 struct dump_table_aux *aux = aux_;
1225 size_t x;
1226
1227 /* Skip UUID columns on the first pass, since their values tend to be
1228 * random and make our results less reproducible. */
1229 for (x = 0; x < aux->n_columns; x++) {
1230 if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
1231 int cmp = compare_data(a_y, b_y, x, aux);
1232 if (cmp) {
1233 return cmp;
1234 }
1235 }
1236 }
1237
1238 /* Use UUID columns as tie-breakers. */
1239 for (x = 0; x < aux->n_columns; x++) {
1240 if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
1241 int cmp = compare_data(a_y, b_y, x, aux);
1242 if (cmp) {
1243 return cmp;
1244 }
1245 }
1246 }
1247
1248 return 0;
1249 }
1250
1251 static void
1252 swap_rows(size_t a_y, size_t b_y, void *aux_)
1253 {
1254 struct dump_table_aux *aux = aux_;
1255 struct ovsdb_datum *tmp = aux->data[a_y];
1256 aux->data[a_y] = aux->data[b_y];
1257 aux->data[b_y] = tmp;
1258 }
1259
1260 static int
1261 compare_columns(const void *a_, const void *b_)
1262 {
1263 const struct ovsdb_column *const *ap = a_;
1264 const struct ovsdb_column *const *bp = b_;
1265 const struct ovsdb_column *a = *ap;
1266 const struct ovsdb_column *b = *bp;
1267
1268 return strcmp(a->name, b->name);
1269 }
1270
1271 static void
1272 dump_table(const char *table_name, const struct shash *cols,
1273 struct json_array *rows)
1274 {
1275 const struct ovsdb_column **columns;
1276 size_t n_columns;
1277
1278 struct ovsdb_datum **data;
1279
1280 struct dump_table_aux aux;
1281 struct shash_node *node;
1282 struct table t;
1283 size_t x, y;
1284
1285 /* Sort columns by name, for reproducibility. */
1286 columns = xmalloc(shash_count(cols) * sizeof *columns);
1287 n_columns = 0;
1288 SHASH_FOR_EACH (node, cols) {
1289 struct ovsdb_column *column = node->data;
1290 if (strcmp(column->name, "_version")) {
1291 columns[n_columns++] = column;
1292 }
1293 }
1294 qsort(columns, n_columns, sizeof *columns, compare_columns);
1295
1296 /* Extract data from table. */
1297 data = xmalloc(rows->n * sizeof *data);
1298 for (y = 0; y < rows->n; y++) {
1299 struct shash *row;
1300
1301 if (rows->elems[y]->type != JSON_OBJECT) {
1302 ovs_fatal(0, "row %"PRIuSIZE" in table %s response is not a JSON object: "
1303 "%s", y, table_name, json_to_string(rows->elems[y], 0));
1304 }
1305 row = json_object(rows->elems[y]);
1306
1307 data[y] = xmalloc(n_columns * sizeof **data);
1308 for (x = 0; x < n_columns; x++) {
1309 const struct json *json = shash_find_data(row, columns[x]->name);
1310 if (!json) {
1311 ovs_fatal(0, "row %"PRIuSIZE" in table %s response lacks %s column",
1312 y, table_name, columns[x]->name);
1313 }
1314
1315 check_ovsdb_error(ovsdb_unconstrained_datum_from_json(
1316 &data[y][x], &columns[x]->type, json));
1317 }
1318 }
1319
1320 /* Sort rows by column values, for reproducibility. */
1321 aux.data = data;
1322 aux.columns = columns;
1323 aux.n_columns = n_columns;
1324 sort(rows->n, compare_rows, swap_rows, &aux);
1325
1326 /* Add column headings. */
1327 table_init(&t);
1328 table_set_caption(&t, xasprintf("%s table", table_name));
1329 for (x = 0; x < n_columns; x++) {
1330 table_add_column(&t, "%s", columns[x]->name);
1331 }
1332
1333 /* Print rows. */
1334 for (y = 0; y < rows->n; y++) {
1335 table_add_row(&t);
1336 for (x = 0; x < n_columns; x++) {
1337 struct cell *cell = table_add_cell(&t);
1338 cell->json = ovsdb_datum_to_json(&data[y][x], &columns[x]->type);
1339 cell->type = &columns[x]->type;
1340 ovsdb_datum_destroy(&data[y][x], &columns[x]->type);
1341 }
1342 free(data[y]);
1343 }
1344 table_print(&t, &table_style);
1345 table_destroy(&t);
1346
1347 free(data);
1348 free(columns);
1349 }
1350
1351 static void
1352 do_dump(struct jsonrpc *rpc, const char *database,
1353 int argc, char *argv[])
1354 {
1355 struct jsonrpc_msg *request, *reply;
1356 struct ovsdb_schema *schema;
1357 struct json *transaction;
1358
1359 const struct shash_node *node, **tables;
1360 size_t n_tables;
1361 struct ovsdb_table_schema *tschema;
1362 const struct shash *columns;
1363 struct shash custom_columns;
1364
1365 size_t i;
1366
1367 shash_init(&custom_columns);
1368 schema = fetch_schema(rpc, database);
1369 if (argc) {
1370 node = shash_find(&schema->tables, argv[0]);
1371 if (!node) {
1372 ovs_fatal(0, "No table \"%s\" found.", argv[0]);
1373 }
1374 tables = xmemdup(&node, sizeof node);
1375 n_tables = 1;
1376 tschema = tables[0]->data;
1377 for (i = 1; i < argc; i++) {
1378 node = shash_find(&tschema->columns, argv[i]);
1379 if (!node) {
1380 ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[1]);
1381 }
1382 shash_add(&custom_columns, argv[1], node->data);
1383 }
1384 } else {
1385 tables = shash_sort(&schema->tables);
1386 n_tables = shash_count(&schema->tables);
1387 }
1388
1389 /* Construct transaction to retrieve entire database. */
1390 transaction = json_array_create_1(json_string_create(database));
1391 for (i = 0; i < n_tables; i++) {
1392 const struct ovsdb_table_schema *ts = tables[i]->data;
1393 struct json *op, *jcolumns;
1394
1395 if (argc > 1) {
1396 columns = &custom_columns;
1397 } else {
1398 columns = &ts->columns;
1399 }
1400 jcolumns = json_array_create_empty();
1401 SHASH_FOR_EACH (node, columns) {
1402 const struct ovsdb_column *column = node->data;
1403
1404 if (strcmp(column->name, "_version")) {
1405 json_array_add(jcolumns, json_string_create(column->name));
1406 }
1407 }
1408
1409 op = json_object_create();
1410 json_object_put_string(op, "op", "select");
1411 json_object_put_string(op, "table", tables[i]->name);
1412 json_object_put(op, "where", json_array_create_empty());
1413 json_object_put(op, "columns", jcolumns);
1414 json_array_add(transaction, op);
1415 }
1416
1417 /* Send request, get reply. */
1418 request = jsonrpc_create_request("transact", transaction, NULL);
1419 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
1420
1421 /* Print database contents. */
1422 if (reply->result->type != JSON_ARRAY
1423 || reply->result->u.array.n != n_tables) {
1424 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
1425 n_tables, json_to_string(reply->result, 0));
1426 }
1427 for (i = 0; i < n_tables; i++) {
1428 const struct ovsdb_table_schema *ts = tables[i]->data;
1429 const struct json *op_result = reply->result->u.array.elems[i];
1430 struct json *rows;
1431
1432 if (op_result->type != JSON_OBJECT
1433 || !(rows = shash_find_data(json_object(op_result), "rows"))
1434 || rows->type != JSON_ARRAY) {
1435 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1436 "member array: %s",
1437 ts->name, json_to_string(op_result, 0));
1438 }
1439
1440 if (argc > 1) {
1441 dump_table(tables[i]->name, &custom_columns, &rows->u.array);
1442 } else {
1443 dump_table(tables[i]->name, &ts->columns, &rows->u.array);
1444 }
1445 }
1446
1447 jsonrpc_msg_destroy(reply);
1448 shash_destroy(&custom_columns);
1449 free(tables);
1450 ovsdb_schema_destroy(schema);
1451 }
1452
1453 static void
1454 print_and_free_log_record(struct json *record)
1455 {
1456 struct ds header = DS_EMPTY_INITIALIZER;
1457 struct ds data = DS_EMPTY_INITIALIZER;
1458 ovsdb_log_compose_record(record, OVSDB_MAGIC, &header, &data);
1459 fwrite(header.string, header.length, 1, stdout);
1460 fwrite(data.string, data.length, 1, stdout);
1461 ds_destroy(&data);
1462 ds_destroy(&header);
1463 json_destroy(record);
1464 }
1465
1466 static void
1467 do_backup(struct jsonrpc *rpc, const char *database,
1468 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1469 {
1470 if (isatty(STDOUT_FILENO)) {
1471 ovs_fatal(0, "not writing backup to a terminal; "
1472 "please redirect stdout to a file");
1473 }
1474
1475 /* Get schema. */
1476 struct ovsdb_schema *schema = fetch_schema(rpc, database);
1477
1478 /* Construct transaction to retrieve all tables. */
1479 struct json *txn = json_array_create_1(json_string_create(database));
1480 struct shash_node *node;
1481 SHASH_FOR_EACH (node, &schema->tables) {
1482 const char *table_name = node->name;
1483 const struct ovsdb_table_schema *table = node->data;
1484
1485 /* Get all the columns except _version and the ephemeral ones.
1486 *
1487 * We don't omit tables that only have ephemeral columns because of the
1488 * possibility that other tables references rows in those tables; that
1489 * is, even if all the columns are ephemeral, the rows themselves are
1490 * not. */
1491 struct json *columns = json_array_create_empty();
1492 struct shash_node *node2;
1493 SHASH_FOR_EACH (node2, &table->columns) {
1494 const struct ovsdb_column *column = node2->data;
1495
1496 if (column->persistent) {
1497 if (!columns) {
1498 columns = json_array_create_empty();
1499 }
1500 json_array_add(columns, json_string_create(column->name));
1501 }
1502 }
1503
1504 struct json *op = json_object_create();
1505 json_object_put_string(op, "op", "select");
1506 json_object_put_string(op, "table", table_name);
1507 json_object_put(op, "where", json_array_create_empty());
1508 json_object_put(op, "columns", columns);
1509 json_array_add(txn, op);
1510 }
1511
1512 /* Send request, get reply. */
1513 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
1514 struct jsonrpc_msg *reply;
1515 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
1516
1517 /* Print schema record. */
1518 print_and_free_log_record(ovsdb_schema_to_json(schema));
1519
1520 /* Print database transaction record. */
1521 if (reply->result->type != JSON_ARRAY
1522 || reply->result->u.array.n != shash_count(&schema->tables)) {
1523 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
1524 shash_count(&schema->tables),
1525 json_to_string(reply->result, 0));
1526 }
1527 struct json *output_txn = json_object_create();
1528
1529 size_t i = 0;
1530 SHASH_FOR_EACH (node, &schema->tables) {
1531 const char *table_name = node->name;
1532 const struct ovsdb_table_schema *table = node->data;
1533 const struct json *op_result = reply->result->u.array.elems[i++];
1534 struct json *rows;
1535
1536 if (op_result->type != JSON_OBJECT
1537 || !(rows = shash_find_data(json_object(op_result), "rows"))
1538 || rows->type != JSON_ARRAY) {
1539 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1540 "member array: %s",
1541 table->name, json_to_string(op_result, 0));
1542 }
1543
1544 if (!rows->u.array.n) {
1545 continue;
1546 }
1547
1548 struct json *output_rows = json_object_create();
1549 for (size_t j = 0; j < rows->u.array.n; j++) {
1550 struct json *row = rows->u.array.elems[j];
1551 if (row->type != JSON_OBJECT) {
1552 ovs_fatal(0, "%s table reply row is not an object: %s",
1553 table_name, json_to_string(row, 0));
1554 }
1555
1556 struct json *uuid_json = shash_find_and_delete(json_object(row),
1557 "_uuid");
1558 if (!uuid_json) {
1559 ovs_fatal(0, "%s table reply row lacks _uuid member: %s",
1560 table_name, json_to_string(row, 0));
1561 }
1562
1563 const struct ovsdb_base_type uuid_base = OVSDB_BASE_UUID_INIT;
1564 union ovsdb_atom atom;
1565 check_ovsdb_error(ovsdb_atom_from_json(&atom, &uuid_base,
1566 uuid_json, NULL));
1567
1568 char uuid_s[UUID_LEN + 1];
1569 snprintf(uuid_s, sizeof uuid_s, UUID_FMT, UUID_ARGS(&atom.uuid));
1570 json_object_put(output_rows, uuid_s, json_clone(row));
1571 }
1572 json_object_put(output_txn, table_name, output_rows);
1573 }
1574 output_txn = ovsdb_file_txn_annotate(
1575 output_txn, "produced by \"ovsdb-client backup\"");
1576 print_and_free_log_record(output_txn);
1577
1578 ovsdb_schema_destroy(schema);
1579 jsonrpc_msg_destroy(reply);
1580 }
1581
1582 static void
1583 do_restore(struct jsonrpc *rpc, const char *database,
1584 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1585 {
1586 if (isatty(STDIN_FILENO)) {
1587 ovs_fatal(0, "not reading backup from a terminal; "
1588 "please redirect stdin from a file");
1589 }
1590
1591 struct ovsdb *backup;
1592 check_ovsdb_error(ovsdb_file_open("/dev/stdin", true, &backup, NULL));
1593
1594 const struct ovsdb_schema *schema = backup->schema;
1595 struct ovsdb_schema *schema2 = fetch_schema(rpc, database);
1596 if (!ovsdb_schema_equal(schema, schema2)) {
1597 struct ds s = DS_EMPTY_INITIALIZER;
1598 if (strcmp(schema->version, schema2->version)) {
1599 ds_put_format(&s, "backup schema has version \"%s\" but "
1600 "database schema has version \"%s\"",
1601 schema->version, schema2->version);
1602 } else {
1603 ds_put_format(&s, "backup schema and database schema are "
1604 "both version %s but still differ",
1605 schema->version);
1606 }
1607 if (!force) {
1608 ovs_fatal(0, "%s (use --force to override differences, or "
1609 "\"ovsdb-client convert\" to change the schema)",
1610 ds_cstr(&s));
1611 }
1612 VLOG_INFO("%s", ds_cstr(&s));
1613 ds_destroy(&s);
1614 }
1615 ovsdb_schema_destroy(schema2);
1616
1617 struct json *txn = json_array_create_empty();
1618 json_array_add(txn, json_string_create(schema->name));
1619 struct shash_node *node;
1620 SHASH_FOR_EACH (node, &backup->tables) {
1621 const char *table_name = node->name;
1622 struct ovsdb_table *table = node->data;
1623
1624 struct json *del_op = json_object_create();
1625 json_object_put_string(del_op, "op", "delete");
1626 json_object_put_string(del_op, "table", table_name);
1627 json_object_put(del_op, "where", json_array_create_empty());
1628 json_array_add(txn, del_op);
1629
1630 const struct ovsdb_row *row;
1631 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
1632 struct json *ins_op = json_object_create();
1633 json_object_put_string(ins_op, "op", "insert");
1634 json_object_put_string(ins_op, "table", table_name);
1635 json_object_put(ins_op, "uuid-name",
1636 json_string_create_nocopy(
1637 ovsdb_data_row_name(ovsdb_row_get_uuid(row))));
1638 struct json *row_json = json_object_create();
1639 json_object_put(ins_op, "row", row_json);
1640
1641 struct shash_node *node2;
1642 SHASH_FOR_EACH (node2, &table->schema->columns) {
1643 const struct ovsdb_column *column = node2->data;
1644 const struct ovsdb_datum *datum = &row->fields[column->index];
1645 const struct ovsdb_type *type = &column->type;
1646 if (column->persistent
1647 && column->index >= OVSDB_N_STD_COLUMNS
1648 && !ovsdb_datum_is_default(datum, type)) {
1649 struct json *value = ovsdb_datum_to_json_with_row_names(
1650 datum, type);
1651 json_object_put(row_json, column->name, value);
1652 }
1653 }
1654 json_array_add(txn, ins_op);
1655 }
1656 }
1657 ovsdb_destroy(backup);
1658 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
1659 struct jsonrpc_msg *reply;
1660 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
1661 if (reply->result->type != JSON_ARRAY) {
1662 ovs_fatal(0, "result is not array");
1663 }
1664 for (size_t i = 0; i < json_array(reply->result)->n; i++) {
1665 struct json *json = json_array(reply->result)->elems[i];
1666 if (json->type != JSON_OBJECT) {
1667 ovs_fatal(0, "result array element is not object");
1668 }
1669 struct shash *object = json_object(json);
1670 if (shash_find(object, "error")) {
1671 ovs_fatal(0, "server returned error reply: %s",
1672 json_to_string(json, JSSF_SORT));
1673 }
1674 }
1675 jsonrpc_msg_destroy(reply);
1676 }
1677
1678
1679 static void
1680 do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
1681 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1682 {
1683 usage();
1684 }
1685
1686 \f
1687 /* "lock" command. */
1688
1689 struct ovsdb_client_lock_req {
1690 const char *method;
1691 char *lock;
1692 };
1693
1694 static void
1695 lock_req_init(struct ovsdb_client_lock_req *lock_req,
1696 const char *method, const char *lock_name)
1697 {
1698 if (lock_req->method || lock_req->lock) {
1699 return;
1700 }
1701 lock_req->method = method;
1702 lock_req->lock = xstrdup(lock_name);
1703 }
1704
1705 static bool
1706 lock_req_is_set(struct ovsdb_client_lock_req *lock_req)
1707 {
1708 return lock_req->method;
1709 }
1710
1711 static void
1712 lock_req_destroy(struct ovsdb_client_lock_req *lock_req)
1713 {
1714 free(lock_req->lock);
1715 lock_req->method = NULL;
1716 lock_req->lock = NULL;
1717 }
1718
1719 /* Create a lock class request. Caller is responsible for free
1720 * the 'request' message. */
1721 static struct jsonrpc_msg *
1722 create_lock_request(struct ovsdb_client_lock_req *lock_req)
1723 {
1724 struct json *locks, *lock;
1725
1726 locks = json_array_create_empty();
1727 lock = json_string_create(lock_req->lock);
1728 json_array_add(locks, lock);
1729
1730 return jsonrpc_create_request(lock_req->method, locks, NULL);
1731 }
1732
1733 static void
1734 ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED,
1735 const char *argv[], void *lock_req_)
1736 {
1737 struct ovsdb_client_lock_req *lock_req = lock_req_;
1738 lock_req_init(lock_req, "lock", argv[1]);
1739 unixctl_command_reply(conn, NULL);
1740 }
1741
1742 static void
1743 ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED,
1744 const char *argv[], void *lock_req_)
1745 {
1746 struct ovsdb_client_lock_req *lock_req = lock_req_;
1747 lock_req_init(lock_req, "unlock", argv[1]);
1748 unixctl_command_reply(conn, NULL);
1749 }
1750
1751 static void
1752 ovsdb_client_steal(struct unixctl_conn *conn, int argc OVS_UNUSED,
1753 const char *argv[], void *lock_req_)
1754 {
1755 struct ovsdb_client_lock_req *lock_req = lock_req_;
1756 lock_req_init(lock_req, "steal", argv[1]);
1757 unixctl_command_reply(conn, NULL);
1758 }
1759
1760 static void
1761 do_lock(struct jsonrpc *rpc, const char *method, const char *lock)
1762 {
1763 struct ovsdb_client_lock_req lock_req = {NULL, NULL};
1764 struct unixctl_server *unixctl;
1765 struct jsonrpc_msg *request;
1766 struct json *request_id = NULL;
1767 bool exiting = false;
1768 bool enable_lock_request = true; /* Don't send another request before
1769 getting a reply of the previous
1770 request. */
1771 daemon_save_fd(STDOUT_FILENO);
1772 daemonize_start(false);
1773 lock_req_init(&lock_req, method, lock);
1774
1775 if (get_detach()) {
1776 int error;
1777
1778 error = unixctl_server_create(NULL, &unixctl);
1779 if (error) {
1780 ovs_fatal(error, "failed to create unixctl server");
1781 }
1782
1783 unixctl_command_register("unlock", "LOCK", 1, 1,
1784 ovsdb_client_unlock, &lock_req);
1785 unixctl_command_register("steal", "LOCK", 1, 1,
1786 ovsdb_client_steal, &lock_req);
1787 unixctl_command_register("lock", "LOCK", 1, 1,
1788 ovsdb_client_lock, &lock_req);
1789 unixctl_command_register("exit", "", 0, 0,
1790 ovsdb_client_exit, &exiting);
1791 } else {
1792 unixctl = NULL;
1793 }
1794
1795 for (;;) {
1796 struct jsonrpc_msg *msg;
1797 int error;
1798
1799 unixctl_server_run(unixctl);
1800 if (enable_lock_request && lock_req_is_set(&lock_req)) {
1801 request = create_lock_request(&lock_req);
1802 request_id = json_clone(request->id);
1803 jsonrpc_send(rpc, request);
1804 lock_req_destroy(&lock_req);
1805 }
1806
1807 error = jsonrpc_recv(rpc, &msg);
1808 if (error == EAGAIN) {
1809 goto no_msg;
1810 } else if (error) {
1811 ovs_fatal(error, "%s: receive failed", jsonrpc_get_name(rpc));
1812 }
1813
1814 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1815 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1816 msg->id));
1817 } else if (msg->type == JSONRPC_REPLY
1818 && json_equal(msg->id, request_id)) {
1819 print_json(msg->result);
1820 fflush(stdout);
1821 enable_lock_request = true;
1822 json_destroy(request_id);
1823 request_id = NULL;
1824 daemonize_complete();
1825 } else if (msg->type == JSONRPC_NOTIFY) {
1826 puts(msg->method);
1827 print_json(msg->params);
1828 fflush(stdout);
1829 }
1830
1831 jsonrpc_msg_destroy(msg);
1832
1833 no_msg:
1834 if (exiting) {
1835 break;
1836 }
1837
1838 jsonrpc_run(rpc);
1839 jsonrpc_wait(rpc);
1840 jsonrpc_recv_wait(rpc);
1841
1842 unixctl_server_wait(unixctl);
1843 poll_block();
1844 }
1845
1846 json_destroy(request_id);
1847 unixctl_server_destroy(unixctl);
1848 }
1849
1850 static void
1851 do_lock_create(struct jsonrpc *rpc, const char *database OVS_UNUSED,
1852 int argc OVS_UNUSED, char *argv[])
1853 {
1854 do_lock(rpc, "lock", argv[0]);
1855 }
1856
1857 static void
1858 do_lock_steal(struct jsonrpc *rpc, const char *database OVS_UNUSED,
1859 int argc OVS_UNUSED, char *argv[])
1860 {
1861 do_lock(rpc, "steal", argv[0]);
1862 }
1863
1864 static void
1865 do_lock_unlock(struct jsonrpc *rpc, const char *database OVS_UNUSED,
1866 int argc OVS_UNUSED, char *argv[])
1867 {
1868 do_lock(rpc, "unlock", argv[0]);
1869 }
1870
1871 /* All command handlers (except for "help") are expected to take an optional
1872 * server socket name (e.g. "unix:...") as their first argument. The socket
1873 * name argument must be included in max_args (but left out of min_args). The
1874 * command name and socket name are not included in the arguments passed to the
1875 * handler: the argv[0] passed to the handler is the first argument after the
1876 * optional server socket name. The connection to the server is available as
1877 * global variable 'rpc'. */
1878 static const struct ovsdb_client_command all_commands[] = {
1879 { "list-dbs", NEED_RPC, 0, 0, do_list_dbs },
1880 { "get-schema", NEED_DATABASE, 0, 0, do_get_schema },
1881 { "get-schema-version", NEED_DATABASE, 0, 0, do_get_schema_version },
1882 { "get-schema-cksum", NEED_DATABASE, 0, 0, do_get_schema_cksum },
1883 { "list-tables", NEED_DATABASE, 0, 0, do_list_tables },
1884 { "list-columns", NEED_DATABASE, 0, 1, do_list_columns },
1885 { "transact", NEED_RPC, 1, 1, do_transact },
1886 { "query", NEED_RPC, 1, 1, do_query },
1887 { "monitor", NEED_DATABASE, 1, INT_MAX, do_monitor },
1888 { "monitor-cond", NEED_DATABASE, 2, 3, do_monitor_cond },
1889 { "dump", NEED_DATABASE, 0, INT_MAX, do_dump },
1890 { "backup", NEED_DATABASE, 0, 0, do_backup },
1891 { "restore", NEED_DATABASE, 0, 0, do_restore },
1892 { "lock", NEED_RPC, 1, 1, do_lock_create },
1893 { "steal", NEED_RPC, 1, 1, do_lock_steal },
1894 { "unlock", NEED_RPC, 1, 1, do_lock_unlock },
1895 { "help", NEED_NONE, 0, INT_MAX, do_help },
1896
1897 { NULL, 0, 0, 0, NULL },
1898 };
1899
1900 static const struct ovsdb_client_command *get_all_commands(void)
1901 {
1902 return all_commands;
1903 }