]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/ovsdb-client.c
Eliminate "whitelist" and "blacklist" terms.
[mirror_ovs.git] / ovsdb / ovsdb-client.c
CommitLineData
d0632593 1/*
2b03ef95 2 * Copyright (c) 2009-2017 Nicira, Inc.
d0632593
BP
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
53ffefe9 19#include <ctype.h>
d0632593 20#include <errno.h>
cb8cbbbe 21#include <fcntl.h>
d0632593
BP
22#include <getopt.h>
23#include <limits.h>
24#include <signal.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include "command-line.h"
30#include "column.h"
31#include "compiler.h"
3f262d7d 32#include "daemon.h"
53ffefe9 33#include "dirs.h"
3e8a2ad1 34#include "openvswitch/dynamic-string.h"
8a777cf6 35#include "fatal-signal.h"
4d0a31b6 36#include "file.h"
ee89ea7b 37#include "openvswitch/json.h"
d0632593 38#include "jsonrpc.h"
3a3eb9da 39#include "lib/table.h"
4d0a31b6 40#include "log.h"
d0632593 41#include "ovsdb.h"
c3a0bfd5 42#include "ovsdb-data.h"
d0632593 43#include "ovsdb-error.h"
1b1d2e6d 44#include "ovsdb-session.h"
fd016ae3 45#include "openvswitch/poll-loop.h"
fe0fb885 46#include "row.h"
25c269ef 47#include "sort.h"
9a614624 48#include "svec.h"
1b1d2e6d 49#include "storage.h"
d0632593 50#include "stream.h"
9467fe62 51#include "stream-ssl.h"
d0632593 52#include "table.h"
1b1d2e6d 53#include "transaction.h"
85226894 54#include "monitor.h"
c383f3bf 55#include "condition.h"
d0632593 56#include "timeval.h"
4227b221 57#include "unixctl.h"
d0632593 58#include "util.h"
e6211adc 59#include "openvswitch/vlog.h"
5136ce49 60
d98e6007 61VLOG_DEFINE_THIS_MODULE(ovsdb_client);
d0632593 62
53ffefe9
BP
63enum args_needed {
64 NEED_NONE, /* No JSON-RPC connection or database name needed. */
65 NEED_RPC, /* JSON-RPC connection needed. */
66 NEED_DATABASE /* JSON-RPC connection and database name needed. */
67};
68
69struct ovsdb_client_command {
70 const char *name;
71 enum args_needed need;
72 int min_args;
73 int max_args;
74 void (*handler)(struct jsonrpc *rpc, const char *database,
75 int argc, char *argv[]);
76};
77
8f46c9bb
BP
78/* --timestamp: Print a timestamp before each update on "monitor" command? */
79static bool timestamp;
80
10621d79
BP
81/* --db-change-aware, --no-db-change-aware: Enable db_change_aware feature for
82 * "monitor" command?
83 *
53178986
BP
84 * -1 (default): Use db_change_aware if available.
85 * 0: Disable db_change_aware.
86 * 1: Require db_change_aware.
87 *
88 * (This option is undocumented because anything other than the default is
89 * expected to be useful only for testing that the db_change_aware feature
90 * actually works.) */
91static int db_change_aware = -1;
10621d79 92
fe0fb885
BP
93/* --force: Ignore schema differences for "restore" command? */
94static bool force;
95
1b1d2e6d
BP
96/* --leader-only, --no-leader-only: Only accept the leader in a cluster. */
97static bool leader_only = true;
98
3a3eb9da
BP
99/* Format for table output. */
100static struct table_style table_style = TABLE_STYLE_DEFAULT;
c3a0bfd5 101
3815d6c2 102static const struct ovsdb_client_command *get_all_commands(void);
d0632593 103
1b1d2e6d
BP
104static struct json *parse_json(const char *);
105
cab50449 106OVS_NO_RETURN static void usage(void);
d0632593 107static void parse_options(int argc, char *argv[]);
53ffefe9 108static struct jsonrpc *open_jsonrpc(const char *server);
9a614624 109static void fetch_dbs(struct jsonrpc *, struct svec *dbs);
1b1d2e6d
BP
110static bool should_stay_connected(const char *server, const char *database,
111 const struct uuid *cid,
112 const struct jsonrpc_msg *reply);
113struct jsonrpc_msg *create_database_info_request(const char *database);
114
115static char *
116default_remote(void)
117{
118 return xasprintf("unix:%s/db.sock", ovs_rundir());
119}
120
121static int
122open_rpc(int min_args, enum args_needed need,
123 int argc, char *argv[], struct jsonrpc **rpcp, char **databasep)
124{
125 struct svec remotes = SVEC_EMPTY_INITIALIZER;
126 struct uuid cid = UUID_ZERO;
127
128 /* First figure out the remote(s). If the first command-line argument has
129 * the form of a remote, use it, otherwise use the default. */
130 int argidx = 0;
131 if (argc > min_args && (isalpha((unsigned char) argv[0][0])
132 && strchr(argv[0], ':'))) {
133 ovsdb_session_parse_remote(argv[argidx++], &remotes, &cid);
134 } else {
135 svec_add_nocopy(&remotes, default_remote());
136 }
137
138 /* Handle the case where there's one remote. In this case, if we need a
139 * database name, we try to figure out a default if none was specified
140 * explicitly. */
141 char *database = *databasep;
142 if (remotes.n == 1) {
143 struct jsonrpc *rpc = open_jsonrpc(remotes.names[0]);
144 svec_destroy(&remotes);
145
146 if (need == NEED_DATABASE && !database) {
147 struct svec dbs;
148
149 svec_init(&dbs);
150 fetch_dbs(rpc, &dbs);
151 if (argc - argidx > min_args
152 && svec_contains(&dbs, argv[argidx])) {
153 database = xstrdup(argv[argidx++]);
154 } else if (svec_contains(&dbs, "Open_vSwitch")) {
155 database = xstrdup("Open_vSwitch");
156 } else {
157 size_t n = 0;
158 const char *best = NULL;
159 for (size_t i = 0; i < dbs.n; i++) {
160 if (dbs.names[i][0] != '_') {
161 best = dbs.names[i];
162 n++;
163 }
164 }
165 if (n != 1) {
166 jsonrpc_close(rpc);
167 ovs_fatal(0, "could not find a default database, "
168 "please specify a database name");
169 }
170 database = xstrdup(best);
171 }
172 svec_destroy(&dbs);
173 }
174 *rpcp = rpc;
175 *databasep = database;
176
177 return argidx;
178 }
179
180 /* If there's more than one remote, and we need a database name, then it
181 * must be specified explicitly. It's too likely to cause surprising
182 * behavior if we try to pick a default across several servers. */
183 if (!database && need == NEED_DATABASE) {
184 if (argc - argidx > min_args) {
185 database = xstrdup(argv[argidx++]);
186 } else {
187 ovs_fatal(0, "database name is required with multiple remotes");
188 }
189 }
190
191 /* We have multiple remotes. Connect to them in a random order and choose
192 * the first one that is up and hosts the database we want (if any) in an
193 * acceptable state. */
194 struct jsonrpc_session *js = jsonrpc_session_open_multiple(
195 &remotes, false);
196 svec_destroy(&remotes);
197
198 unsigned int seqno = 0;
199 struct json *id = NULL;
200 for (;;) {
201 jsonrpc_session_run(js);
202 if (!jsonrpc_session_is_alive(js)) {
203 ovs_fatal(0, "no servers were available");
204 }
205
206 if (seqno != jsonrpc_session_get_seqno(js)
207 && jsonrpc_session_is_connected(js)) {
208 if (!database) {
209 break;
210 }
211
212 seqno = jsonrpc_session_get_seqno(js);
213 struct jsonrpc_msg *txn = create_database_info_request(database);
214 json_destroy(id);
215 id = json_clone(txn->id);
216 jsonrpc_session_send(js, txn);
217 }
218
219 struct jsonrpc_msg *reply = jsonrpc_session_recv(js);
220 if (reply && id && reply->id && json_equal(id, reply->id)) {
221 if (reply->type == JSONRPC_REPLY
222 && should_stay_connected(jsonrpc_session_get_name(js),
223 database, &cid, reply)) {
224 jsonrpc_msg_destroy(reply);
225 break;
226 }
227 jsonrpc_session_force_reconnect(js);
228 }
229 jsonrpc_msg_destroy(reply);
230
231 jsonrpc_session_recv_wait(js);
232 jsonrpc_session_wait(js);
233 poll_block();
234 }
235 json_destroy(id);
236
237 *rpcp = jsonrpc_session_steal(js);
238 *databasep = database;
239 return argidx;
240}
d0632593
BP
241
242int
243main(int argc, char *argv[])
244{
53ffefe9 245 const struct ovsdb_client_command *command;
5f383751 246 ovs_cmdl_proctitle_init(argc, argv);
d0632593 247 set_program_name(argv[0]);
fe559381 248 service_start(&argc, &argv);
d0632593 249 parse_options(argc, argv);
8a777cf6 250 fatal_ignore_sigpipe();
53ffefe9 251
e91b927d 252 daemon_become_new_user(false);
53ffefe9
BP
253 if (optind >= argc) {
254 ovs_fatal(0, "missing command name; use --help for help");
255 }
256
3815d6c2 257 for (command = get_all_commands(); ; command++) {
53ffefe9
BP
258 if (!command->name) {
259 VLOG_FATAL("unknown command '%s'; use --help for help",
260 argv[optind]);
261 } else if (!strcmp(command->name, argv[optind])) {
262 break;
263 }
264 }
265 optind++;
266
1b1d2e6d
BP
267 char *database = NULL;
268 struct jsonrpc *rpc = NULL;
53ffefe9 269 if (command->need != NEED_NONE) {
1b1d2e6d
BP
270 optind += open_rpc(command->min_args, command->need,
271 argc - optind, argv + optind, &rpc, &database);
53ffefe9
BP
272 }
273
53ffefe9
BP
274
275 if (argc - optind < command->min_args ||
276 argc - optind > command->max_args) {
880f5c03 277 free(database);
53ffefe9
BP
278 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
279 command->name);
280 }
281
282 command->handler(rpc, database, argc - optind, argv + optind);
283
af65491d 284 free(database);
53ffefe9
BP
285 jsonrpc_close(rpc);
286
287 if (ferror(stdout)) {
288 VLOG_FATAL("write to stdout failed");
289 }
290 if (ferror(stderr)) {
291 VLOG_FATAL("write to stderr failed");
292 }
293
d0632593
BP
294 return 0;
295}
296
297static void
298parse_options(int argc, char *argv[])
299{
9467fe62 300 enum {
8274ae95 301 OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
8f46c9bb 302 OPT_TIMESTAMP,
fe0fb885 303 OPT_FORCE,
1b1d2e6d
BP
304 OPT_LEADER_ONLY,
305 OPT_NO_LEADER_ONLY,
1af09488 306 VLOG_OPTION_ENUMS,
8274ae95 307 DAEMON_OPTION_ENUMS,
e18a1d08
ER
308 TABLE_OPTION_ENUMS,
309 SSL_OPTION_ENUMS,
9467fe62 310 };
07fc4ed3 311 static const struct option long_options[] = {
e3c17733
BP
312 {"help", no_argument, NULL, 'h'},
313 {"version", no_argument, NULL, 'V'},
8f46c9bb 314 {"timestamp", no_argument, NULL, OPT_TIMESTAMP},
fe0fb885 315 {"force", no_argument, NULL, OPT_FORCE},
c55d0b7b 316 {"timeout", required_argument, NULL, 't'},
10621d79
BP
317 {"db-change-aware", no_argument, &db_change_aware, 1},
318 {"no-db-change-aware", no_argument, &db_change_aware, 0},
1b1d2e6d
BP
319 {"leader-only", no_argument, NULL, OPT_LEADER_ONLY},
320 {"no-leader-only", no_argument, NULL, OPT_NO_LEADER_ONLY},
1af09488 321 VLOG_LONG_OPTIONS,
3f262d7d 322 DAEMON_LONG_OPTIONS,
9467fe62 323#ifdef HAVE_OPENSSL
e3c17733 324 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
bf8f2167 325 STREAM_SSL_LONG_OPTIONS,
9467fe62 326#endif
bf8f2167 327 TABLE_LONG_OPTIONS,
e3c17733 328 {NULL, 0, NULL, 0},
d0632593 329 };
5f383751 330 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
9551e80b 331 unsigned int timeout = 0;
d0632593 332
c4817da7
LR
333 table_style.format = TF_TABLE;
334
d0632593
BP
335 for (;;) {
336 int c;
337
338 c = getopt_long(argc, argv, short_options, long_options, NULL);
339 if (c == -1) {
340 break;
341 }
342
343 switch (c) {
d0632593
BP
344 case 'h':
345 usage();
346
347 case 'V':
55d5bb44 348 ovs_print_version(0, 0);
d0632593
BP
349 exit(EXIT_SUCCESS);
350
1af09488 351 VLOG_OPTION_HANDLERS
3f262d7d 352 DAEMON_OPTION_HANDLERS
3a3eb9da 353 TABLE_OPTION_HANDLERS(&table_style)
9467fe62
BP
354 STREAM_SSL_OPTION_HANDLERS
355
356 case OPT_BOOTSTRAP_CA_CERT:
357 stream_ssl_set_ca_cert_file(optarg, true);
358 break;
9467fe62 359
8f46c9bb
BP
360 case OPT_TIMESTAMP:
361 timestamp = true;
362 break;
363
fe0fb885
BP
364 case OPT_FORCE:
365 force = true;
366 break;
367
c55d0b7b 368 case 't':
cbcf40a8
IM
369 if (!str_to_uint(optarg, 10, &timeout) || !timeout) {
370 ovs_fatal(0, "value %s on -t or --timeout is invalid", optarg);
c55d0b7b
BP
371 }
372 break;
373
1b1d2e6d
BP
374 case OPT_LEADER_ONLY:
375 leader_only = true;
376 break;
377
378 case OPT_NO_LEADER_ONLY:
379 leader_only = false;
380 break;
381
d0632593
BP
382 case '?':
383 exit(EXIT_FAILURE);
384
385 case 0:
386 /* getopt_long() already set the value for us. */
387 break;
388
389 default:
390 abort();
391 }
392 }
393 free(short_options);
9551e80b
IM
394
395 ctl_timeout_setup(timeout);
d0632593
BP
396}
397
398static void
399usage(void)
400{
401 printf("%s: Open vSwitch database JSON-RPC client\n"
402 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
403 "\nValid commands are:\n"
53ffefe9 404 "\n list-dbs [SERVER]\n"
9cb53f26 405 " list databases available on SERVER\n"
53ffefe9 406 "\n get-schema [SERVER] [DATABASE]\n"
9cb53f26 407 " retrieve schema for DATABASE from SERVER\n"
53ffefe9 408 "\n get-schema-version [SERVER] [DATABASE]\n"
8159b984
BP
409 " retrieve schema for DATABASE from SERVER and report only its\n"
410 " version number on stdout\n"
33785c07
BP
411 "\n get-schema-cksum [SERVER] [DATABASE]\n"
412 " retrieve schema for DATABASE from SERVER and report only its\n"
413 " checksum on stdout\n"
53ffefe9 414 "\n list-tables [SERVER] [DATABASE]\n"
25c269ef 415 " list tables for DATABASE on SERVER\n"
53ffefe9 416 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
9cb53f26 417 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
53ffefe9 418 "\n transact [SERVER] TRANSACTION\n"
838f9c31 419 " run TRANSACTION (params for \"transact\" request) on SERVER\n"
a8425c53 420 " and print the results as JSON on stdout\n"
838f9c31
BP
421 "\n query [SERVER] TRANSACTION\n"
422 " run TRANSACTION (params for \"transact\" request) on SERVER,\n"
423 " as read-only, and print the results as JSON on stdout\n"
53ffefe9 424 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
20aa445d
BP
425 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
426 " COLUMNs may include !initial, !insert, !delete, !modify\n"
427 " to avoid seeing the specified kinds of changes.\n"
c383f3bf
LS
428 "\n monitor-cond [SERVER] [DATABASE] CONDITION TABLE [COLUMN,...]...\n"
429 " monitor contents that match CONDITION of COLUMNs in TABLE in\n"
430 " DATABASE on SERVER.\n"
431 " COLUMNs may include !initial, !insert, !delete, !modify\n"
432 " to avoid seeing the specified kinds of changes.\n"
9167cb52
HZ
433 "\n monitor-cond-since [SERVER] [DATABASE] [LASTID] CONDITION TABLE [COLUMN,...]...\n"
434 " monitor contents that match CONDITION of COLUMNs in TABLE in\n"
435 " DATABASE on SERVER, since change after LASTID.\n"
436 " LASTID specifies transaction ID after which the monitoring\n"
437 " starts, which works only for cluster mode. If ignored, it\n"
438 " defaults to an all-zero uuid.\n"
439 " Other arguments are the same as in monitor-cond.\n"
53178986
BP
440 "\n convert [SERVER] SCHEMA\n"
441 " convert database on SERVER named in SCHEMA to SCHEMA.\n"
442 "\n needs-conversion [SERVER] SCHEMA\n"
443 " tests whether SCHEMA's db on SERVER needs conversion.\n"
4227b221
BP
444 "\n monitor [SERVER] [DATABASE] ALL\n"
445 " monitor all changes to all columns in all tables\n"
1b1d2e6d
BP
446 "\n wait [SERVER] DATABASE STATE\n"
447 " wait until DATABASE reaches STATE "
448 "(\"added\" or \"connected\" or \"removed\")\n"
4227b221 449 " in DATBASE on SERVER.\n"
85226894 450 "\n dump [SERVER] [DATABASE]\n"
53ffefe9 451 " dump contents of DATABASE on SERVER to stdout\n"
fe0fb885 452 "\n backup [SERVER] [DATABASE] > SNAPSHOT\n"
4d0a31b6 453 " dump database contents in the form of a database file\n"
fe0fb885
BP
454 "\n [--force] restore [SERVER] [DATABASE] < SNAPSHOT\n"
455 " restore database contents from a database file\n"
9aeba3f4
AZ
456 "\n lock [SERVER] LOCK\n"
457 " create or wait for LOCK in SERVER\n"
458 "\n steal [SERVER] LOCK\n"
459 " steal LOCK from SERVER\n"
460 "\n unlock [SERVER] LOCK\n"
461 " unlock LOCK from SERVER\n"
53ffefe9
BP
462 "\nThe default SERVER is unix:%s/db.sock.\n"
463 "The default DATABASE is Open_vSwitch.\n",
464 program_name, program_name, ovs_rundir());
9467fe62 465 stream_usage("SERVER", true, true, true);
bcb58ce0
LR
466 table_usage();
467 printf(" --timestamp timestamp \"monitor\" output");
3f262d7d 468 daemon_usage();
d0632593
BP
469 vlog_usage();
470 printf("\nOther options:\n"
471 " -h, --help display this help message\n"
472 " -V, --version display version information\n");
473 exit(EXIT_SUCCESS);
474}
475\f
d35f8e72
EJ
476static void
477check_txn(int error, struct jsonrpc_msg **reply_)
478{
479 struct jsonrpc_msg *reply = *reply_;
480
481 if (error) {
482 ovs_fatal(error, "transaction failed");
483 }
484
485 if (reply->error) {
486 ovs_fatal(error, "transaction returned error: %s",
487 json_to_string(reply->error, table_style.json_flags));
488 }
489}
490
6d65eee8
BP
491static struct json *
492parse_json(const char *s)
493{
494 struct json *json = json_from_string(s);
495 if (json->type == JSON_STRING) {
fa37affa 496 ovs_fatal(0, "\"%s\": %s", s, json->string);
6d65eee8
BP
497 }
498 return json;
499}
500
d0632593
BP
501static struct jsonrpc *
502open_jsonrpc(const char *server)
503{
504 struct stream *stream;
505 int error;
506
f125905c 507 error = stream_open_block(jsonrpc_stream_open(server, &stream,
77f42ca5 508 DSCP_DEFAULT), -1, &stream);
1b0f0f17
BP
509 if (error == EAFNOSUPPORT) {
510 struct pstream *pstream;
511
f125905c 512 error = jsonrpc_pstream_open(server, &pstream, DSCP_DEFAULT);
1b0f0f17
BP
513 if (error) {
514 ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
515 }
516
517 VLOG_INFO("%s: waiting for connection...", server);
518 error = pstream_accept_block(pstream, &stream);
519 if (error) {
520 ovs_fatal(error, "failed to accept connection on \"%s\"", server);
521 }
522
523 pstream_close(pstream);
524 } else if (error) {
d0632593
BP
525 ovs_fatal(error, "failed to connect to \"%s\"", server);
526 }
527
528 return jsonrpc_open(stream);
529}
530
531static void
532print_json(struct json *json)
533{
3a3eb9da 534 char *string = json_to_string(json, table_style.json_flags);
838f9c31 535 puts(string);
d0632593
BP
536 free(string);
537}
538
539static void
540print_and_free_json(struct json *json)
541{
542 print_json(json);
543 json_destroy(json);
544}
545
546static void
547check_ovsdb_error(struct ovsdb_error *error)
548{
549 if (error) {
550 ovs_fatal(0, "%s", ovsdb_error_to_string(error));
551 }
552}
553
554static struct ovsdb_schema *
53ffefe9 555fetch_schema(struct jsonrpc *rpc, const char *database)
d0632593
BP
556{
557 struct jsonrpc_msg *request, *reply;
558 struct ovsdb_schema *schema;
d0632593 559
9cb53f26
BP
560 request = jsonrpc_create_request("get_schema",
561 json_array_create_1(
562 json_string_create(database)),
20bed8be 563 NULL);
d35f8e72 564 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
d0632593
BP
565 check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
566 jsonrpc_msg_destroy(reply);
a8425c53
BP
567
568 return schema;
569}
570
9cb53f26 571static void
9a614624 572fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
9cb53f26
BP
573{
574 struct jsonrpc_msg *request, *reply;
9cb53f26
BP
575 size_t i;
576
9cb53f26
BP
577 request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
578 NULL);
9cb53f26 579
d35f8e72 580 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
9cb53f26
BP
581 if (reply->result->type != JSON_ARRAY) {
582 ovs_fatal(0, "list_dbs response is not array");
583 }
584
fa37affa
BP
585 for (i = 0; i < reply->result->array.n; i++) {
586 const struct json *name = reply->result->array.elems[i];
9cb53f26
BP
587
588 if (name->type != JSON_STRING) {
34582733 589 ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i);
9cb53f26 590 }
fa37affa 591 svec_add(dbs, name->string);
9cb53f26
BP
592 }
593 jsonrpc_msg_destroy(reply);
71fceeb0 594 svec_sort(dbs);
9cb53f26 595}
1b1d2e6d
BP
596
597static const char *
598parse_string_column(const struct json *row, const char *column_name)
599{
600 const struct json *column = shash_find_data(json_object(row), column_name);
601 return column && column->type == JSON_STRING ? json_string(column) : "";
602}
603
604static int
605parse_boolean_column(const struct json *row, const char *column_name)
606{
607 const struct json *column = shash_find_data(json_object(row), column_name);
608 return (!column ? -1
609 : column->type == JSON_TRUE ? true
610 : column->type == JSON_FALSE ? false
611 : -1);
612}
613
614static struct uuid
615parse_uuid_column(const struct json *row, const char *column_name)
616{
617 const struct json *column = shash_find_data(json_object(row), column_name);
618 if (!column) {
619 return UUID_ZERO;
620 }
621
622 struct ovsdb_type type = { OVSDB_BASE_UUID_INIT, OVSDB_BASE_VOID_INIT,
623 0, 1 };
624 struct ovsdb_datum datum;
625 struct ovsdb_error *error = ovsdb_datum_from_json(&datum, &type, column,
626 NULL);
627 if (error) {
628 ovsdb_error_destroy(error);
629 return UUID_ZERO;
630 }
631 struct uuid uuid = datum.n > 0 ? datum.keys[0].uuid : UUID_ZERO;
632 ovsdb_datum_destroy(&datum, &type);
633 return uuid;
634}
635
636struct jsonrpc_msg *
637create_database_info_request(const char *database)
638{
639 struct json *op = json_object_create();
640 json_object_put_string(op, "op", "select");
641 json_object_put_string(op, "table", "Database");
642 struct json *condition = json_array_create_3(
643 json_string_create("name"),
644 json_string_create("=="),
645 json_string_create(database));
646 json_object_put(op, "where", json_array_create_1(condition));
647 struct json *txn = json_array_create_2(
648 json_string_create("_Server"), op);
649 return jsonrpc_create_request("transact", txn, NULL);
650}
651
652static const struct json *
653parse_database_info_reply(const struct jsonrpc_msg *reply, const char *server,
654 const char *database, const struct uuid *cid)
655{
656 const struct json *result = reply->result;
657 if (result->type != JSON_ARRAY
fa37affa
BP
658 || result->array.n != 1
659 || result->array.elems[0]->type != JSON_OBJECT) {
1b1d2e6d
BP
660 VLOG_WARN("%s: unexpected reply to _Server request for %s",
661 server, database);
662 return NULL;
663 }
664
fa37affa 665 const struct json *op_result = result->array.elems[0];
1b1d2e6d
BP
666 const struct json *rows = shash_find_data(json_object(op_result), "rows");
667 if (!rows || rows->type != JSON_ARRAY) {
668 VLOG_WARN("%s: missing \"rows\" member in _Server reply for %s",
669 server, database);
670 return NULL;
671 }
672
fa37affa
BP
673 for (size_t i = 0; i < rows->array.n; i++) {
674 const struct json *row = rows->array.elems[i];
1b1d2e6d
BP
675 if (row->type != JSON_OBJECT) {
676 VLOG_WARN("%s: bad row in _Server reply for %s",
677 server, database);
678 continue;
679 }
680
681 if (strcmp(parse_string_column(row, "name"), database)) {
682 continue;
683 }
684
685 if (cid && !uuid_is_zero(cid)) {
686 struct uuid cid2 = parse_uuid_column(row, "cid");
687 if (!uuid_equals(cid, &cid2)) {
688 continue;
689 }
690 }
691
692 return row;
693 }
694
695 /* No such database. */
696 return NULL;
697}
698
699/* Parses 'reply', a JSON-RPC reply to our request asking for the status of
700 * 'database' on 'server'. Determines whether this server is acceptable for
701 * the transaction we want to make and returns true if so or false to
702 * disconnect and try a different server. */
703static bool
704should_stay_connected(const char *server, const char *database,
705 const struct uuid *cid, const struct jsonrpc_msg *reply)
706{
707 const struct json *row = parse_database_info_reply(reply, server,
708 database, cid);
709 if (!row) {
710 /* No such database. */
711 return false;
712 }
713
714 if (strcmp(parse_string_column(row, "model"), "clustered")) {
715 /* Always accept standalone databases. */
716 return true;
717 }
718
719 if (!parse_boolean_column(row, "connected")) {
720 /* Reject disconnected servers. */
721 return false;
722 }
723
724 if (leader_only && !parse_boolean_column(row, "leader")) {
725 /* Reject if not leader.. */
726 return false;
727 }
728
729 return true;
730}
53ffefe9
BP
731\f
732static void
733do_list_dbs(struct jsonrpc *rpc, const char *database OVS_UNUSED,
734 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
735{
736 const char *db_name;
9a614624
BP
737 struct svec dbs;
738 size_t i;
53ffefe9 739
9a614624 740 svec_init(&dbs);
53ffefe9 741 fetch_dbs(rpc, &dbs);
9a614624 742 SVEC_FOR_EACH (i, db_name, &dbs) {
53ffefe9
BP
743 puts(db_name);
744 }
9a614624 745 svec_destroy(&dbs);
53ffefe9 746}
9cb53f26 747
d0632593 748static void
53ffefe9
BP
749do_get_schema(struct jsonrpc *rpc, const char *database,
750 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593 751{
53ffefe9 752 struct ovsdb_schema *schema = fetch_schema(rpc, database);
d0632593
BP
753 print_and_free_json(ovsdb_schema_to_json(schema));
754 ovsdb_schema_destroy(schema);
755}
756
8159b984 757static void
53ffefe9
BP
758do_get_schema_version(struct jsonrpc *rpc, const char *database,
759 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
8159b984 760{
53ffefe9 761 struct ovsdb_schema *schema = fetch_schema(rpc, database);
8159b984
BP
762 puts(schema->version);
763 ovsdb_schema_destroy(schema);
764}
765
33785c07
BP
766static void
767do_get_schema_cksum(struct jsonrpc *rpc, const char *database,
768 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
769{
770 struct ovsdb_schema *schema = fetch_schema(rpc, database);
771 puts(schema->cksum);
772 ovsdb_schema_destroy(schema);
773}
774
d0632593 775static void
53ffefe9
BP
776do_list_tables(struct jsonrpc *rpc, const char *database,
777 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593
BP
778{
779 struct ovsdb_schema *schema;
780 struct shash_node *node;
781 struct table t;
782
53ffefe9 783 schema = fetch_schema(rpc, database);
d0632593
BP
784 table_init(&t);
785 table_add_column(&t, "Table");
d0632593
BP
786 SHASH_FOR_EACH (node, &schema->tables) {
787 struct ovsdb_table_schema *ts = node->data;
788
789 table_add_row(&t);
772387d5 790 table_add_cell(&t)->text = xstrdup(ts->name);
d0632593
BP
791 }
792 ovsdb_schema_destroy(schema);
3a3eb9da 793 table_print(&t, &table_style);
af65491d 794 table_destroy(&t);
d0632593
BP
795}
796
797static void
53ffefe9
BP
798do_list_columns(struct jsonrpc *rpc, const char *database,
799 int argc OVS_UNUSED, char *argv[])
d0632593 800{
53ffefe9 801 const char *table_name = argv[0];
d0632593
BP
802 struct ovsdb_schema *schema;
803 struct shash_node *table_node;
804 struct table t;
805
53ffefe9 806 schema = fetch_schema(rpc, database);
d0632593
BP
807 table_init(&t);
808 if (!table_name) {
809 table_add_column(&t, "Table");
810 }
811 table_add_column(&t, "Column");
812 table_add_column(&t, "Type");
d0632593
BP
813 SHASH_FOR_EACH (table_node, &schema->tables) {
814 struct ovsdb_table_schema *ts = table_node->data;
815
816 if (!table_name || !strcmp(table_name, ts->name)) {
817 struct shash_node *column_node;
818
819 SHASH_FOR_EACH (column_node, &ts->columns) {
bd76d25d 820 const struct ovsdb_column *column = column_node->data;
d0632593
BP
821
822 table_add_row(&t);
823 if (!table_name) {
772387d5 824 table_add_cell(&t)->text = xstrdup(ts->name);
d0632593 825 }
772387d5
BP
826 table_add_cell(&t)->text = xstrdup(column->name);
827 table_add_cell(&t)->json = ovsdb_type_to_json(&column->type);
d0632593
BP
828 }
829 }
830 }
831 ovsdb_schema_destroy(schema);
3a3eb9da 832 table_print(&t, &table_style);
af65491d 833 table_destroy(&t);
d0632593
BP
834}
835
53178986
BP
836static void
837send_db_change_aware(struct jsonrpc *rpc)
838{
839 if (db_change_aware != 0) {
840 struct jsonrpc_msg *request = jsonrpc_create_request(
841 "set_db_change_aware",
842 json_array_create_1(json_boolean_create(true)),
843 NULL);
844 struct jsonrpc_msg *reply;
845 int error = jsonrpc_transact_block(rpc, request, &reply);
846 if (error) {
847 ovs_fatal(error, "%s: error setting db_change_aware",
848 jsonrpc_get_name(rpc));
849 }
850 if (reply->type == JSONRPC_ERROR && db_change_aware == 1) {
851 ovs_fatal(0, "%s: set_db_change_aware failed (%s)",
852 jsonrpc_get_name(rpc), json_to_string(reply->error, 0));
853 }
854 jsonrpc_msg_destroy(reply);
855 }
856}
857
838f9c31 858static struct json *
1b1d2e6d 859do_transact__(int argc, char *argv[], struct json *transaction)
6d65eee8
BP
860{
861 struct jsonrpc_msg *request, *reply;
1b1d2e6d 862 if (transaction->type != JSON_ARRAY
fa37affa
BP
863 || !transaction->array.n
864 || transaction->array.elems[0]->type != JSON_STRING) {
1b1d2e6d
BP
865 ovs_fatal(0, "not a valid OVSDB query");
866 }
fa37affa 867 const char *db_name = json_string(transaction->array.elems[0]);
1b1d2e6d
BP
868
869 struct jsonrpc *rpc;
870 char *database = CONST_CAST(char *, db_name);
871 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
6d65eee8 872
53178986
BP
873 if (db_change_aware == 1) {
874 send_db_change_aware(rpc);
875 }
876 daemon_save_fd(STDOUT_FILENO);
877 daemon_save_fd(STDERR_FILENO);
878 daemonize();
879
20bed8be 880 request = jsonrpc_create_request("transact", transaction, NULL);
d35f8e72 881 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
838f9c31 882 struct json *result = json_clone(reply->result);
6d65eee8 883 jsonrpc_msg_destroy(reply);
1b1d2e6d 884 jsonrpc_close(rpc);
838f9c31
BP
885
886 return result;
887}
888
889static void
1b1d2e6d
BP
890do_transact(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
891 int argc, char *argv[])
838f9c31 892{
1b1d2e6d 893 print_and_free_json(do_transact__(argc, argv, parse_json(argv[argc - 1])));
838f9c31
BP
894}
895
896static void
1b1d2e6d
BP
897do_query(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
898 int argc, char *argv[])
838f9c31 899{
1b1d2e6d 900 struct json *transaction = parse_json(argv[argc - 1]);
838f9c31
BP
901
902 if (transaction->type != JSON_ARRAY) {
903 ovs_fatal(0, "not a valid OVSDB query");
904 }
905
906 /* Append an "abort" operation to the query. */
907 struct json *abort_op = json_object_create();
908 json_object_put_string(abort_op, "op", "abort");
909 json_array_add(transaction, abort_op);
fa37affa 910 size_t abort_idx = transaction->array.n - 2;
838f9c31
BP
911
912 /* Run query. */
1b1d2e6d 913 struct json *result = do_transact__(argc, argv, transaction);
838f9c31
BP
914
915 /* If the "abort" operation ended the transaction, remove its result. */
916 if (result->type == JSON_ARRAY
fa37affa
BP
917 && result->array.n == abort_idx + 1
918 && result->array.elems[abort_idx]->type == JSON_OBJECT) {
919 struct json *op_result = result->array.elems[abort_idx];
838f9c31
BP
920 struct json *error = shash_find_data(json_object(op_result), "error");
921 if (error
922 && error->type == JSON_STRING
923 && !strcmp(json_string(error), "aborted")) {
fa37affa 924 result->array.n--;
838f9c31
BP
925 json_destroy(op_result);
926 }
927 }
928
929 /* Print the result. */
930 print_and_free_json(result);
6d65eee8 931}
4227b221
BP
932\f
933/* "monitor" command. */
934
935struct monitored_table {
936 struct ovsdb_table_schema *table;
937 struct ovsdb_column_set columns;
938};
6d65eee8 939
a8425c53
BP
940static void
941monitor_print_row(struct json *row, const char *type, const char *uuid,
942 const struct ovsdb_column_set *columns, struct table *t)
943{
944 size_t i;
945
946 if (!row) {
947 ovs_error(0, "missing %s row", type);
948 return;
949 } else if (row->type != JSON_OBJECT) {
950 ovs_error(0, "<row> is not object");
951 return;
952 }
953
954 table_add_row(t);
772387d5
BP
955 table_add_cell(t)->text = xstrdup(uuid);
956 table_add_cell(t)->text = xstrdup(type);
a8425c53
BP
957 for (i = 0; i < columns->n_columns; i++) {
958 const struct ovsdb_column *column = columns->columns[i];
959 struct json *value = shash_find_data(json_object(row), column->name);
772387d5 960 struct cell *cell = table_add_cell(t);
a8425c53 961 if (value) {
772387d5
BP
962 cell->json = json_clone(value);
963 cell->type = &column->type;
a8425c53
BP
964 }
965 }
966}
967
968static void
4227b221
BP
969monitor_print_table(struct json *table_update,
970 const struct monitored_table *mt, char *caption,
971 bool initial)
a8425c53 972{
4227b221
BP
973 const struct ovsdb_table_schema *table = mt->table;
974 const struct ovsdb_column_set *columns = &mt->columns;
a8425c53
BP
975 struct shash_node *node;
976 struct table t;
977 size_t i;
978
a8425c53 979 if (table_update->type != JSON_OBJECT) {
4227b221 980 ovs_error(0, "<table-update> for table %s is not object", table->name);
a8425c53
BP
981 return;
982 }
983
4227b221
BP
984 table_init(&t);
985 table_set_timestamp(&t, timestamp);
986 table_set_caption(&t, caption);
987
a8425c53
BP
988 table_add_column(&t, "row");
989 table_add_column(&t, "action");
990 for (i = 0; i < columns->n_columns; i++) {
991 table_add_column(&t, "%s", columns->columns[i]->name);
992 }
993 SHASH_FOR_EACH (node, json_object(table_update)) {
994 struct json *row_update = node->data;
995 struct json *old, *new;
996
997 if (row_update->type != JSON_OBJECT) {
998 ovs_error(0, "<row-update> is not object");
999 continue;
1000 }
1001 old = shash_find_data(json_object(row_update), "old");
1002 new = shash_find_data(json_object(row_update), "new");
1003 if (initial) {
1004 monitor_print_row(new, "initial", node->name, columns, &t);
1005 } else if (!old) {
1006 monitor_print_row(new, "insert", node->name, columns, &t);
1007 } else if (!new) {
1008 monitor_print_row(old, "delete", node->name, columns, &t);
1009 } else {
1010 monitor_print_row(old, "old", node->name, columns, &t);
1011 monitor_print_row(new, "new", "", columns, &t);
1012 }
1013 }
3a3eb9da 1014 table_print(&t, &table_style);
a8425c53
BP
1015 table_destroy(&t);
1016}
1017
4227b221
BP
1018static void
1019monitor_print(struct json *table_updates,
1020 const struct monitored_table *mts, size_t n_mts,
1021 bool initial)
1022{
1023 size_t i;
1024
1025 if (table_updates->type != JSON_OBJECT) {
1026 ovs_error(0, "<table-updates> is not object");
1027 return;
1028 }
1029
1030 for (i = 0; i < n_mts; i++) {
1031 const struct monitored_table *mt = &mts[i];
1032 struct json *table_update = shash_find_data(json_object(table_updates),
1033 mt->table->name);
1034 if (table_update) {
1035 monitor_print_table(table_update, mt,
1036 n_mts > 1 ? xstrdup(mt->table->name) : NULL,
1037 initial);
1038 }
1039 }
1040}
1041
85226894
AZ
1042static void
1043monitor2_print_row(struct json *row, const char *type, const char *uuid,
1044 const struct ovsdb_column_set *columns, struct table *t)
1045{
1046 if (!strcmp(type, "delete")) {
1047 if (row->type != JSON_NULL) {
1048 ovs_error(0, "delete method does not expect <row>");
1049 return;
1050 }
1051
1052 table_add_row(t);
1053 table_add_cell(t)->text = xstrdup(uuid);
1054 table_add_cell(t)->text = xstrdup(type);
1055 } else {
1056 if (!row || row->type != JSON_OBJECT) {
1057 ovs_error(0, "<row> is not object");
1058 return;
1059 }
1060 monitor_print_row(row, type, uuid, columns, t);
1061 }
1062}
1063
1064static void
1065monitor2_print_table(struct json *table_update2,
1066 const struct monitored_table *mt, char *caption)
1067{
1068 const struct ovsdb_table_schema *table = mt->table;
1069 const struct ovsdb_column_set *columns = &mt->columns;
1070 struct shash_node *node;
1071 struct table t;
85226894
AZ
1072
1073 if (table_update2->type != JSON_OBJECT) {
1074 ovs_error(0, "<table-update> for table %s is not object", table->name);
1075 return;
1076 }
1077
1078 table_init(&t);
1079 table_set_timestamp(&t, timestamp);
1080 table_set_caption(&t, caption);
1081
1082 table_add_column(&t, "row");
1083 table_add_column(&t, "action");
17573cf1 1084 for (size_t i = 0; i < columns->n_columns; i++) {
85226894
AZ
1085 table_add_column(&t, "%s", columns->columns[i]->name);
1086 }
1087 SHASH_FOR_EACH (node, json_object(table_update2)) {
1088 struct json *row_update2 = node->data;
1089 const char *operation;
1090 struct json *row;
1091 const char *ops[] = {"delete", "initial", "modify", "insert"};
1092
1093 if (row_update2->type != JSON_OBJECT) {
1094 ovs_error(0, "<row-update2> is not object");
1095 continue;
1096 }
1097
1098 /* row_update2 contains one of objects indexed by ops[] */
1099 for (int i = 0; i < ARRAY_SIZE(ops); i++) {
1100 operation = ops[i];
1101 row = shash_find_data(json_object(row_update2), operation);
1102
1103 if (row) {
1104 monitor2_print_row(row, operation, node->name, columns, &t);
1105 break;
1106 }
1107 }
1108 }
1109 table_print(&t, &table_style);
1110 table_destroy(&t);
1111}
1112
1113static void
1114monitor2_print(struct json *table_updates2,
1115 const struct monitored_table *mts, size_t n_mts)
1116{
1117 size_t i;
1118
1119 if (table_updates2->type != JSON_OBJECT) {
1120 ovs_error(0, "<table-updates2> is not object");
1121 return;
1122 }
1123
1124 for (i = 0; i < n_mts; i++) {
1125 const struct monitored_table *mt = &mts[i];
1126 struct json *table_update = shash_find_data(
1127 json_object(table_updates2),
1128 mt->table->name);
1129 if (table_update) {
1130 monitor2_print_table(table_update, mt,
1131 n_mts > 1 ? xstrdup(mt->table->name) : NULL);
1132 }
1133 }
1134}
1135
9167cb52
HZ
1136static void
1137monitor3_print(struct json *result,
1138 const struct monitored_table *mts, size_t n_mts)
1139{
1140 if (result->type != JSON_ARRAY) {
1141 ovs_error(0, "<result> is not array");
1142 }
1143
1144 if (result->array.n != 3) {
1145 ovs_error(0, "<result> should have 3 elements, but has %"PRIuSIZE".",
1146 result->array.n);
1147 }
1148
1149 bool found = json_boolean(result->array.elems[0]);
1150 const char *last_id = json_string(result->array.elems[1]);
1151 printf("found: %s, last_id: %s\n", found ? "true" : "false", last_id);
1152
1153 struct json *table_updates2 = result->array.elems[2];
1154 monitor2_print(table_updates2, mts, n_mts);
1155}
1156
1157static void
1158monitor3_notify_print(const char *last_id, struct json *table_updates2,
1159 const struct monitored_table *mts, size_t n_mts)
1160{
1161 printf("\nlast_id: %s", last_id);
1162 monitor2_print(table_updates2, mts, n_mts);
1163}
1164
a8425c53 1165static void
20aa445d
BP
1166add_column(const char *server, const struct ovsdb_column *column,
1167 struct ovsdb_column_set *columns, struct json *columns_json)
a8425c53 1168{
20aa445d
BP
1169 if (ovsdb_column_set_contains(columns, column->index)) {
1170 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
1171 server, column->name);
a8425c53 1172 }
20aa445d
BP
1173 ovsdb_column_set_add(columns, column);
1174 json_array_add(columns_json, json_string_create(column->name));
1175}
a8425c53 1176
20aa445d
BP
1177static struct json *
1178parse_monitor_columns(char *arg, const char *server, const char *database,
1179 const struct ovsdb_table_schema *table,
1180 struct ovsdb_column_set *columns)
1181{
1182 bool initial, insert, delete, modify;
1183 struct json *mr, *columns_json;
1184 char *save_ptr = NULL;
1185 char *token;
1186
1187 mr = json_object_create();
1188 columns_json = json_array_create_empty();
1189 json_object_put(mr, "columns", columns_json);
1190
1191 initial = insert = delete = modify = true;
1192 for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
1193 token = strtok_r(NULL, ",", &save_ptr)) {
1194 if (!strcmp(token, "!initial")) {
1195 initial = false;
1196 } else if (!strcmp(token, "!insert")) {
1197 insert = false;
1198 } else if (!strcmp(token, "!delete")) {
1199 delete = false;
1200 } else if (!strcmp(token, "!modify")) {
1201 modify = false;
1202 } else {
a8425c53 1203 const struct ovsdb_column *column;
20aa445d 1204
a8425c53
BP
1205 column = ovsdb_table_schema_get_column(table, token);
1206 if (!column) {
9cb53f26
BP
1207 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
1208 "column named \"%s\"",
20aa445d 1209 server, table->name, database, token);
a8425c53 1210 }
20aa445d 1211 add_column(server, column, columns, columns_json);
a8425c53 1212 }
20aa445d
BP
1213 }
1214
fa37affa 1215 if (columns_json->array.n == 0) {
a1ae5dc8
BP
1216 const struct shash_node **nodes;
1217 size_t i, n;
1218
1219 n = shash_count(&table->columns);
1220 nodes = shash_sort(&table->columns);
1221 for (i = 0; i < n; i++) {
1222 const struct ovsdb_column *column = nodes[i]->data;
1223 if (column->index != OVSDB_COL_UUID
1224 && column->index != OVSDB_COL_VERSION) {
20aa445d 1225 add_column(server, column, columns, columns_json);
a8425c53
BP
1226 }
1227 }
a1ae5dc8
BP
1228 free(nodes);
1229
4227b221 1230 add_column(server, ovsdb_table_schema_get_column(table, "_version"),
20aa445d 1231 columns, columns_json);
a8425c53
BP
1232 }
1233
20aa445d
BP
1234 if (!initial || !insert || !delete || !modify) {
1235 struct json *select = json_object_create();
876ba6de
BP
1236 json_object_put(select, "initial", json_boolean_create(initial));
1237 json_object_put(select, "insert", json_boolean_create(insert));
1238 json_object_put(select, "delete", json_boolean_create(delete));
1239 json_object_put(select, "modify", json_boolean_create(modify));
20aa445d
BP
1240 json_object_put(mr, "select", select);
1241 }
1242
1243 return mr;
1244}
1245
1246static void
4227b221
BP
1247ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
1248 const char *argv[] OVS_UNUSED, void *exiting_)
20aa445d 1249{
4227b221
BP
1250 bool *exiting = exiting_;
1251 *exiting = true;
1252 unixctl_command_reply(conn, NULL);
1253}
20aa445d 1254
4227b221
BP
1255static void
1256ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
1257 const char *argv[] OVS_UNUSED, void *blocked_)
1258{
1259 bool *blocked = blocked_;
1260
1261 if (!*blocked) {
1262 *blocked = true;
1263 unixctl_command_reply(conn, NULL);
1264 } else {
1265 unixctl_command_reply(conn, "already blocking");
a8425c53 1266 }
4227b221
BP
1267}
1268
1269static void
1270ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
1271 const char *argv[] OVS_UNUSED, void *blocked_)
1272{
1273 bool *blocked = blocked_;
1274
1275 if (*blocked) {
1276 *blocked = false;
1277 unixctl_command_reply(conn, NULL);
1278 } else {
1279 unixctl_command_reply(conn, "already unblocked");
1280 }
1281}
1282
c383f3bf
LS
1283static void
1284ovsdb_client_cond_change(struct unixctl_conn *conn, int argc OVS_UNUSED,
1285 const char *argv[], void *rpc_)
1286{
1287 struct jsonrpc *rpc = rpc_;
1288 struct json *monitor_cond_update_requests = json_object_create();
1289 struct json *monitor_cond_update_request = json_object_create();
1290 struct json *params;
1291 struct jsonrpc_msg *request;
1292
1293 json_object_put(monitor_cond_update_request, "where",
1294 json_from_string(argv[2]));
1295 json_object_put(monitor_cond_update_requests,
1296 argv[1],
1297 json_array_create_1(monitor_cond_update_request));
1298
1299 params = json_array_create_3(json_null_create(),json_null_create(),
1300 monitor_cond_update_requests);
1301
1302 request = jsonrpc_create_request("monitor_cond_change", params, NULL);
1303 jsonrpc_send(rpc, request);
1304
1305 VLOG_DBG("cond change %s %s", argv[1], argv[2]);
a3f42026 1306 unixctl_command_reply(conn, "condition changed");
c383f3bf
LS
1307}
1308
4227b221
BP
1309static void
1310add_monitored_table(int argc, char *argv[],
1311 const char *server, const char *database,
c383f3bf 1312 struct json *condition,
4227b221
BP
1313 struct ovsdb_table_schema *table,
1314 struct json *monitor_requests,
1315 struct monitored_table **mts,
1316 size_t *n_mts, size_t *allocated_mts)
1317{
c383f3bf 1318 struct json *monitor_request_array, *mr;
4227b221
BP
1319 struct monitored_table *mt;
1320
1321 if (*n_mts >= *allocated_mts) {
1322 *mts = x2nrealloc(*mts, allocated_mts, sizeof **mts);
1323 }
1324 mt = &(*mts)[(*n_mts)++];
1325 mt->table = table;
1326 ovsdb_column_set_init(&mt->columns);
a8425c53 1327
20aa445d 1328 monitor_request_array = json_array_create_empty();
53ffefe9 1329 if (argc > 1) {
20aa445d
BP
1330 int i;
1331
53ffefe9 1332 for (i = 1; i < argc; i++) {
c383f3bf
LS
1333 mr = parse_monitor_columns(argv[i], server, database, table,
1334 &mt->columns);
1335 if (i == 1 && condition) {
1336 json_object_put(mr, "where", condition);
1337 }
1338 json_array_add(monitor_request_array, mr);
20aa445d
BP
1339 }
1340 } else {
4227b221
BP
1341 /* Allocate a writable empty string since parse_monitor_columns()
1342 * is going to strtok() it and that's risky with literal "". */
20aa445d 1343 char empty[] = "";
c383f3bf
LS
1344
1345 mr = parse_monitor_columns(empty, server, database,
1346 table, &mt->columns);
1347 if (condition) {
1348 json_object_put(mr, "where", condition);
1349 }
1350 json_array_add(monitor_request_array, mr);
4227b221
BP
1351 }
1352
1353 json_object_put(monitor_requests, table->name, monitor_request_array);
1354}
1355
12f554b0
WT
1356static void
1357destroy_monitored_table(struct monitored_table *mts, size_t n)
1358{
1359 int i;
1360
1361 for (i = 0; i < n; i++) {
1362 struct monitored_table *mt = &mts[i];
1363 ovsdb_column_set_destroy(&mt->columns);
1364 }
1365
1366 free(mts);
1367}
1368
4227b221 1369static void
85226894
AZ
1370do_monitor__(struct jsonrpc *rpc, const char *database,
1371 enum ovsdb_monitor_version version,
9167cb52
HZ
1372 int argc, char *argv[], struct json *condition,
1373 const struct uuid *last_id)
4227b221
BP
1374{
1375 const char *server = jsonrpc_get_name(rpc);
1376 const char *table_name = argv[0];
1377 struct unixctl_server *unixctl;
1378 struct ovsdb_schema *schema;
4227b221
BP
1379 struct json *monitor, *monitor_requests, *request_id;
1380 bool exiting = false;
1381 bool blocked = false;
1382
1383 struct monitored_table *mts;
1384 size_t n_mts, allocated_mts;
1385
85226894
AZ
1386 ovs_assert(version < OVSDB_MONITOR_VERSION_MAX);
1387
4227b221 1388 daemon_save_fd(STDOUT_FILENO);
53178986 1389 daemon_save_fd(STDERR_FILENO);
e91b927d 1390 daemonize_start(false);
4227b221
BP
1391 if (get_detach()) {
1392 int error;
1393
1394 error = unixctl_server_create(NULL, &unixctl);
1395 if (error) {
1396 ovs_fatal(error, "failed to create unixctl server");
1397 }
1398
1399 unixctl_command_register("exit", "", 0, 0,
1400 ovsdb_client_exit, &exiting);
1401 unixctl_command_register("ovsdb-client/block", "", 0, 0,
1402 ovsdb_client_block, &blocked);
1403 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
1404 ovsdb_client_unblock, &blocked);
c383f3bf
LS
1405 unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
1406 ovsdb_client_cond_change, rpc);
4227b221
BP
1407 } else {
1408 unixctl = NULL;
a8425c53
BP
1409 }
1410
4227b221
BP
1411 schema = fetch_schema(rpc, database);
1412
a8425c53 1413 monitor_requests = json_object_create();
4227b221
BP
1414
1415 mts = NULL;
1416 n_mts = allocated_mts = 0;
1417 if (strcmp(table_name, "ALL")) {
1418 struct ovsdb_table_schema *table;
1419
1420 table = shash_find_data(&schema->tables, table_name);
1421 if (!table) {
1422 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
1423 server, database, table_name);
1424 }
1425
c383f3bf 1426 add_monitored_table(argc, argv, server, database, condition, table,
4227b221
BP
1427 monitor_requests, &mts, &n_mts, &allocated_mts);
1428 } else {
1429 size_t n = shash_count(&schema->tables);
1430 const struct shash_node **nodes = shash_sort(&schema->tables);
1431 size_t i;
1432
c383f3bf
LS
1433 if (condition) {
1434 ovs_fatal(0, "ALL tables are not allowed with condition");
1435 }
1436
4227b221
BP
1437 for (i = 0; i < n; i++) {
1438 struct ovsdb_table_schema *table = nodes[i]->data;
1439
c383f3bf 1440 add_monitored_table(argc, argv, server, database, NULL, table,
4227b221
BP
1441 monitor_requests,
1442 &mts, &n_mts, &allocated_mts);
1443 }
1444 free(nodes);
1445 }
a8425c53 1446
53178986 1447 send_db_change_aware(rpc);
10621d79 1448
9cb53f26
BP
1449 monitor = json_array_create_3(json_string_create(database),
1450 json_null_create(), monitor_requests);
9167cb52
HZ
1451 const char *method;
1452 switch (version) {
1453 case OVSDB_MONITOR_V1:
1454 method = "monitor";
1455 break;
1456 case OVSDB_MONITOR_V2:
1457 method = "monitor_cond";
1458 break;
1459 case OVSDB_MONITOR_V3:
1460 method = "monitor_cond_since";
1461 struct json *json_last_id = json_string_create_nocopy(
1462 xasprintf(UUID_FMT, UUID_ARGS(last_id)));
1463 json_array_add(monitor, json_last_id);
1464 break;
1465 case OVSDB_MONITOR_VERSION_MAX:
1466 default:
1467 OVS_NOT_REACHED();
1468 }
85226894 1469
10621d79 1470 struct jsonrpc_msg *request;
85226894 1471 request = jsonrpc_create_request(method, monitor, NULL);
a8425c53
BP
1472 request_id = json_clone(request->id);
1473 jsonrpc_send(rpc, request);
a8425c53 1474
4227b221
BP
1475 for (;;) {
1476 unixctl_server_run(unixctl);
1477 while (!blocked) {
1478 struct jsonrpc_msg *msg;
1479 int error;
1480
1481 error = jsonrpc_recv(rpc, &msg);
1482 if (error == EAGAIN) {
1483 break;
1484 } else if (error) {
1485 ovs_fatal(error, "%s: receive failed", server);
eb8d3ed6 1486 }
4227b221
BP
1487
1488 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1489 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1490 msg->id));
1491 } else if (msg->type == JSONRPC_REPLY
1492 && json_equal(msg->id, request_id)) {
85226894
AZ
1493 switch(version) {
1494 case OVSDB_MONITOR_V1:
1495 monitor_print(msg->result, mts, n_mts, true);
1496 break;
1497 case OVSDB_MONITOR_V2:
1498 monitor2_print(msg->result, mts, n_mts);
1499 break;
9167cb52
HZ
1500 case OVSDB_MONITOR_V3:
1501 monitor3_print(msg->result, mts, n_mts);
1502 break;
85226894
AZ
1503 case OVSDB_MONITOR_VERSION_MAX:
1504 default:
1505 OVS_NOT_REACHED();
1506 }
3f262d7d 1507 fflush(stdout);
4227b221
BP
1508 daemonize_complete();
1509 } else if (msg->type == JSONRPC_NOTIFY
1510 && !strcmp(msg->method, "update")) {
1511 struct json *params = msg->params;
1512 if (params->type == JSON_ARRAY
fa37affa
BP
1513 && params->array.n == 2
1514 && params->array.elems[0]->type == JSON_NULL) {
1515 monitor_print(params->array.elems[1], mts, n_mts, false);
4227b221
BP
1516 fflush(stdout);
1517 }
85226894
AZ
1518 } else if (msg->type == JSONRPC_NOTIFY
1519 && version == OVSDB_MONITOR_V2
1520 && !strcmp(msg->method, "update2")) {
1521 struct json *params = msg->params;
1522 if (params->type == JSON_ARRAY
fa37affa
BP
1523 && params->array.n == 2
1524 && params->array.elems[0]->type == JSON_NULL) {
1525 monitor2_print(params->array.elems[1], mts, n_mts);
85226894
AZ
1526 fflush(stdout);
1527 }
9167cb52
HZ
1528 } else if (msg->type == JSONRPC_NOTIFY
1529 && version == OVSDB_MONITOR_V3
1530 && !strcmp(msg->method, "update3")) {
1531 struct json *params = msg->params;
1532 if (params->type == JSON_ARRAY
1533 && params->array.n == 3
1534 && params->array.elems[0]->type == JSON_NULL) {
1535 monitor3_notify_print(json_string(params->array.elems[1]),
1536 params->array.elems[2], mts, n_mts);
1537 fflush(stdout);
1538 }
53178986
BP
1539 } else if (msg->type == JSONRPC_NOTIFY
1540 && !strcmp(msg->method, "monitor_canceled")) {
1541 ovs_fatal(0, "%s: %s database was removed",
1542 server, database);
a8425c53 1543 }
4227b221
BP
1544 jsonrpc_msg_destroy(msg);
1545 }
1546
1547 if (exiting) {
1548 break;
1549 }
1550
1551 jsonrpc_run(rpc);
1552 jsonrpc_wait(rpc);
1553 if (!blocked) {
1554 jsonrpc_recv_wait(rpc);
a8425c53 1555 }
4227b221
BP
1556 unixctl_server_wait(unixctl);
1557 poll_block();
a8425c53 1558 }
c7edc921
WT
1559
1560 json_destroy(request_id);
1561 unixctl_server_destroy(unixctl);
0ea4fd89 1562 ovsdb_schema_destroy(schema);
12f554b0 1563 destroy_monitored_table(mts, n_mts);
a8425c53
BP
1564}
1565
85226894
AZ
1566static void
1567do_monitor(struct jsonrpc *rpc, const char *database,
1568 int argc, char *argv[])
1569{
9167cb52 1570 do_monitor__(rpc, database, OVSDB_MONITOR_V1, argc, argv, NULL, NULL);
85226894
AZ
1571}
1572
1573static void
9167cb52
HZ
1574do_monitor_cond__(struct jsonrpc *rpc, const char *database,
1575 enum ovsdb_monitor_version version,
1576 struct uuid *last_id, int argc, char *argv[])
85226894 1577{
c383f3bf
LS
1578 struct ovsdb_condition cnd;
1579 struct json *condition = NULL;
1580 struct ovsdb_schema *schema;
1581 struct ovsdb_table_schema *table;
1582 const char *table_name = argv[1];
1583
1584 ovs_assert(argc > 1);
1585 schema = fetch_schema(rpc, database);
1586 table = shash_find_data(&schema->tables, table_name);
1587 if (!table) {
1588 ovs_fatal(0, "%s does not have a table named \"%s\"",
1589 database, table_name);
1590 }
1591 condition = parse_json(argv[0]);
1592 check_ovsdb_error(ovsdb_condition_from_json(table, condition,
1593 NULL, &cnd));
1594 ovsdb_condition_destroy(&cnd);
9167cb52
HZ
1595 do_monitor__(rpc, database, version, --argc, ++argv, condition,
1596 last_id);
9b2cc0c3 1597 ovsdb_schema_destroy(schema);
85226894
AZ
1598}
1599
9167cb52
HZ
1600static void
1601do_monitor_cond(struct jsonrpc *rpc, const char *database,
1602 int argc, char *argv[])
1603{
1604 do_monitor_cond__(rpc, database, OVSDB_MONITOR_V2, NULL, argc, argv);
1605}
1606
1607static void
1608do_monitor_cond_since(struct jsonrpc *rpc, const char *database,
1609 int argc, char *argv[])
1610{
1611 ovs_assert(argc > 1);
1612 struct uuid last_id;
1613 if (uuid_from_string(&last_id, argv[0])) {
1614 argc--;
1615 argv++;
1616 }
1617 do_monitor_cond__(rpc, database, OVSDB_MONITOR_V3, &last_id, argc, argv);
1618}
1619
1b1d2e6d
BP
1620static bool
1621is_database_clustered(struct jsonrpc *rpc, const char *database)
1622{
1623 struct jsonrpc_msg *reply;
1624 check_txn(jsonrpc_transact_block(rpc,
1625 create_database_info_request(database),
1626 &reply), &reply);
1627
1628 const struct json *row = parse_database_info_reply(
1629 reply, jsonrpc_get_name(rpc), database, NULL);
a8d36f94
DS
1630 bool clustered = !strcmp(parse_string_column(row, "model"), "clustered");
1631 jsonrpc_msg_destroy(reply);
1632 return clustered;
1b1d2e6d
BP
1633}
1634
53178986 1635static void
1b1d2e6d
BP
1636do_convert(struct jsonrpc *rpc, const char *database_ OVS_UNUSED,
1637 int argc, char *argv[])
53178986 1638{
1b1d2e6d 1639 const char *schema_file_name = argv[argc - 1];
53178986 1640 struct ovsdb_schema *new_schema;
1b1d2e6d
BP
1641 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &new_schema));
1642
1643 char *database = new_schema->name;
1644 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
1645
1646 if (is_database_clustered(rpc, database)) {
1647 ovsdb_schema_persist_ephemeral_columns(new_schema, schema_file_name);
1648 }
1649
1650 send_db_change_aware(rpc);
53178986
BP
1651
1652 struct jsonrpc_msg *request, *reply;
1653 request = jsonrpc_create_request(
1654 "convert",
1655 json_array_create_2(json_string_create(new_schema->name),
1656 ovsdb_schema_to_json(new_schema)), NULL);
1657 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
1658 jsonrpc_msg_destroy(reply);
48d8a65e 1659 ovsdb_schema_destroy(new_schema);
3e020508 1660 jsonrpc_close(rpc);
53178986
BP
1661}
1662
1663static void
1b1d2e6d 1664do_needs_conversion(struct jsonrpc *rpc, const char *database_ OVS_UNUSED,
53178986
BP
1665 int argc OVS_UNUSED, char *argv[])
1666{
1667 struct ovsdb_schema *schema1;
1668 check_ovsdb_error(ovsdb_schema_from_file(argv[0], &schema1));
1669
1b1d2e6d
BP
1670 char *database = schema1->name;
1671 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
1672
1673 if (is_database_clustered(rpc, database)) {
1674 ovsdb_schema_persist_ephemeral_columns(schema1, argv[0]);
1675 }
1676
53178986
BP
1677 struct ovsdb_schema *schema2 = fetch_schema(rpc, schema1->name);
1678 puts(ovsdb_schema_equal(schema1, schema2) ? "no" : "yes");
1679 ovsdb_schema_destroy(schema1);
1680 ovsdb_schema_destroy(schema2);
3e020508 1681 jsonrpc_close(rpc);
53178986
BP
1682}
1683
25c269ef
BP
1684struct dump_table_aux {
1685 struct ovsdb_datum **data;
1686 const struct ovsdb_column **columns;
1687 size_t n_columns;
1688};
1689
1690static int
1691compare_data(size_t a_y, size_t b_y, size_t x,
1692 const struct dump_table_aux *aux)
1693{
1694 return ovsdb_datum_compare_3way(&aux->data[a_y][x],
1695 &aux->data[b_y][x],
1696 &aux->columns[x]->type);
1697}
1698
1699static int
1700compare_rows(size_t a_y, size_t b_y, void *aux_)
1701{
1702 struct dump_table_aux *aux = aux_;
1703 size_t x;
1704
1705 /* Skip UUID columns on the first pass, since their values tend to be
1706 * random and make our results less reproducible. */
1707 for (x = 0; x < aux->n_columns; x++) {
1708 if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
1709 int cmp = compare_data(a_y, b_y, x, aux);
1710 if (cmp) {
1711 return cmp;
1712 }
1713 }
1714 }
1715
1716 /* Use UUID columns as tie-breakers. */
1717 for (x = 0; x < aux->n_columns; x++) {
1718 if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
1719 int cmp = compare_data(a_y, b_y, x, aux);
1720 if (cmp) {
1721 return cmp;
1722 }
1723 }
1724 }
1725
1726 return 0;
1727}
1728
1729static void
1730swap_rows(size_t a_y, size_t b_y, void *aux_)
1731{
1732 struct dump_table_aux *aux = aux_;
1733 struct ovsdb_datum *tmp = aux->data[a_y];
1734 aux->data[a_y] = aux->data[b_y];
1735 aux->data[b_y] = tmp;
1736}
1737
25c269ef
BP
1738static int
1739compare_columns(const void *a_, const void *b_)
1740{
1741 const struct ovsdb_column *const *ap = a_;
1742 const struct ovsdb_column *const *bp = b_;
1743 const struct ovsdb_column *a = *ap;
1744 const struct ovsdb_column *b = *bp;
1745
1746 return strcmp(a->name, b->name);
1747}
1748
1749static void
b30aa413
BV
1750dump_table(const char *table_name, const struct shash *cols,
1751 struct json_array *rows)
25c269ef
BP
1752{
1753 const struct ovsdb_column **columns;
1754 size_t n_columns;
1755
1756 struct ovsdb_datum **data;
1757
1758 struct dump_table_aux aux;
1759 struct shash_node *node;
1760 struct table t;
1761 size_t x, y;
1762
1763 /* Sort columns by name, for reproducibility. */
b30aa413 1764 columns = xmalloc(shash_count(cols) * sizeof *columns);
25c269ef 1765 n_columns = 0;
b30aa413 1766 SHASH_FOR_EACH (node, cols) {
25c269ef
BP
1767 struct ovsdb_column *column = node->data;
1768 if (strcmp(column->name, "_version")) {
1769 columns[n_columns++] = column;
1770 }
1771 }
1772 qsort(columns, n_columns, sizeof *columns, compare_columns);
1773
1774 /* Extract data from table. */
1775 data = xmalloc(rows->n * sizeof *data);
1776 for (y = 0; y < rows->n; y++) {
1777 struct shash *row;
1778
1779 if (rows->elems[y]->type != JSON_OBJECT) {
34582733 1780 ovs_fatal(0, "row %"PRIuSIZE" in table %s response is not a JSON object: "
b30aa413 1781 "%s", y, table_name, json_to_string(rows->elems[y], 0));
25c269ef
BP
1782 }
1783 row = json_object(rows->elems[y]);
1784
1785 data[y] = xmalloc(n_columns * sizeof **data);
1786 for (x = 0; x < n_columns; x++) {
1787 const struct json *json = shash_find_data(row, columns[x]->name);
1788 if (!json) {
34582733 1789 ovs_fatal(0, "row %"PRIuSIZE" in table %s response lacks %s column",
b30aa413 1790 y, table_name, columns[x]->name);
25c269ef
BP
1791 }
1792
9041097a
BP
1793 check_ovsdb_error(ovsdb_unconstrained_datum_from_json(
1794 &data[y][x], &columns[x]->type, json));
25c269ef
BP
1795 }
1796 }
1797
1798 /* Sort rows by column values, for reproducibility. */
1799 aux.data = data;
1800 aux.columns = columns;
1801 aux.n_columns = n_columns;
1802 sort(rows->n, compare_rows, swap_rows, &aux);
1803
1804 /* Add column headings. */
1805 table_init(&t);
b30aa413 1806 table_set_caption(&t, xasprintf("%s table", table_name));
25c269ef
BP
1807 for (x = 0; x < n_columns; x++) {
1808 table_add_column(&t, "%s", columns[x]->name);
1809 }
1810
1811 /* Print rows. */
1812 for (y = 0; y < rows->n; y++) {
1813 table_add_row(&t);
1814 for (x = 0; x < n_columns; x++) {
772387d5
BP
1815 struct cell *cell = table_add_cell(&t);
1816 cell->json = ovsdb_datum_to_json(&data[y][x], &columns[x]->type);
1817 cell->type = &columns[x]->type;
e49190c4 1818 ovsdb_datum_destroy(&data[y][x], &columns[x]->type);
25c269ef 1819 }
e49190c4 1820 free(data[y]);
25c269ef 1821 }
3a3eb9da 1822 table_print(&t, &table_style);
25c269ef 1823 table_destroy(&t);
e49190c4
BP
1824
1825 free(data);
1826 free(columns);
25c269ef
BP
1827}
1828
1829static void
53ffefe9 1830do_dump(struct jsonrpc *rpc, const char *database,
b30aa413 1831 int argc, char *argv[])
25c269ef 1832{
25c269ef
BP
1833 struct jsonrpc_msg *request, *reply;
1834 struct ovsdb_schema *schema;
1835 struct json *transaction;
25c269ef 1836
b30aa413 1837 const struct shash_node *node, **tables;
25c269ef 1838 size_t n_tables;
b30aa413
BV
1839 struct ovsdb_table_schema *tschema;
1840 const struct shash *columns;
1841 struct shash custom_columns;
25c269ef
BP
1842
1843 size_t i;
1844
b30aa413 1845 shash_init(&custom_columns);
53ffefe9 1846 schema = fetch_schema(rpc, database);
b30aa413
BV
1847 if (argc) {
1848 node = shash_find(&schema->tables, argv[0]);
1849 if (!node) {
1850 ovs_fatal(0, "No table \"%s\" found.", argv[0]);
1851 }
2b03ef95 1852 tables = xmemdup(&node, sizeof node);
b30aa413
BV
1853 n_tables = 1;
1854 tschema = tables[0]->data;
1855 for (i = 1; i < argc; i++) {
1856 node = shash_find(&tschema->columns, argv[i]);
1857 if (!node) {
0d5450a2 1858 ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[i]);
b30aa413 1859 }
0d5450a2 1860 shash_add(&custom_columns, argv[i], node->data);
b30aa413
BV
1861 }
1862 } else {
1863 tables = shash_sort(&schema->tables);
1864 n_tables = shash_count(&schema->tables);
1865 }
25c269ef
BP
1866
1867 /* Construct transaction to retrieve entire database. */
1868 transaction = json_array_create_1(json_string_create(database));
1869 for (i = 0; i < n_tables; i++) {
1870 const struct ovsdb_table_schema *ts = tables[i]->data;
b30aa413 1871 struct json *op, *jcolumns;
25c269ef 1872
b30aa413
BV
1873 if (argc > 1) {
1874 columns = &custom_columns;
1875 } else {
1876 columns = &ts->columns;
1877 }
1878 jcolumns = json_array_create_empty();
1879 SHASH_FOR_EACH (node, columns) {
25c269ef
BP
1880 const struct ovsdb_column *column = node->data;
1881
1882 if (strcmp(column->name, "_version")) {
b30aa413 1883 json_array_add(jcolumns, json_string_create(column->name));
25c269ef
BP
1884 }
1885 }
1886
1887 op = json_object_create();
1888 json_object_put_string(op, "op", "select");
1889 json_object_put_string(op, "table", tables[i]->name);
1890 json_object_put(op, "where", json_array_create_empty());
b30aa413 1891 json_object_put(op, "columns", jcolumns);
25c269ef
BP
1892 json_array_add(transaction, op);
1893 }
1894
1895 /* Send request, get reply. */
1896 request = jsonrpc_create_request("transact", transaction, NULL);
d35f8e72 1897 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
25c269ef
BP
1898
1899 /* Print database contents. */
1900 if (reply->result->type != JSON_ARRAY
fa37affa 1901 || reply->result->array.n != n_tables) {
34582733 1902 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
25c269ef
BP
1903 n_tables, json_to_string(reply->result, 0));
1904 }
1905 for (i = 0; i < n_tables; i++) {
1906 const struct ovsdb_table_schema *ts = tables[i]->data;
fa37affa 1907 const struct json *op_result = reply->result->array.elems[i];
25c269ef
BP
1908 struct json *rows;
1909
1910 if (op_result->type != JSON_OBJECT
1911 || !(rows = shash_find_data(json_object(op_result), "rows"))
1912 || rows->type != JSON_ARRAY) {
1913 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1914 "member array: %s",
1915 ts->name, json_to_string(op_result, 0));
1916 }
1917
b30aa413 1918 if (argc > 1) {
fa37affa 1919 dump_table(tables[i]->name, &custom_columns, &rows->array);
b30aa413 1920 } else {
fa37affa 1921 dump_table(tables[i]->name, &ts->columns, &rows->array);
b30aa413 1922 }
25c269ef 1923 }
e49190c4
BP
1924
1925 jsonrpc_msg_destroy(reply);
b30aa413 1926 shash_destroy(&custom_columns);
e49190c4
BP
1927 free(tables);
1928 ovsdb_schema_destroy(schema);
25c269ef
BP
1929}
1930
4d0a31b6
BP
1931static void
1932print_and_free_log_record(struct json *record)
1933{
1934 struct ds header = DS_EMPTY_INITIALIZER;
1935 struct ds data = DS_EMPTY_INITIALIZER;
19b276cb 1936 ovsdb_log_compose_record(record, OVSDB_MAGIC, &header, &data);
4d0a31b6
BP
1937 fwrite(header.string, header.length, 1, stdout);
1938 fwrite(data.string, data.length, 1, stdout);
1939 ds_destroy(&data);
1940 ds_destroy(&header);
1941 json_destroy(record);
1942}
1943
cb8cbbbe
AGS
1944static void
1945set_binary_mode(FILE *stream OVS_UNUSED)
1946{
1947#ifdef _WIN32
1948 fflush(stream);
1949 /* On Windows set binary mode on the file descriptor to avoid
1950 * translation (i.e. CRLF line endings). */
1951 if (_setmode(_fileno(stream), O_BINARY) == -1) {
1952 ovs_fatal(errno, "could not set binary mode on fd %d",
1953 _fileno(stream));
1954 }
1955#endif
1956}
1957
4d0a31b6
BP
1958static void
1959do_backup(struct jsonrpc *rpc, const char *database,
1960 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1961{
1962 if (isatty(STDOUT_FILENO)) {
1963 ovs_fatal(0, "not writing backup to a terminal; "
1964 "please redirect stdout to a file");
1965 }
cb8cbbbe 1966 set_binary_mode(stdout);
4d0a31b6
BP
1967
1968 /* Get schema. */
1969 struct ovsdb_schema *schema = fetch_schema(rpc, database);
1970
1971 /* Construct transaction to retrieve all tables. */
1972 struct json *txn = json_array_create_1(json_string_create(database));
1973 struct shash_node *node;
1974 SHASH_FOR_EACH (node, &schema->tables) {
1975 const char *table_name = node->name;
1976 const struct ovsdb_table_schema *table = node->data;
1977
1978 /* Get all the columns except _version and the ephemeral ones.
1979 *
1980 * We don't omit tables that only have ephemeral columns because of the
1981 * possibility that other tables references rows in those tables; that
1982 * is, even if all the columns are ephemeral, the rows themselves are
1983 * not. */
1984 struct json *columns = json_array_create_empty();
1985 struct shash_node *node2;
1986 SHASH_FOR_EACH (node2, &table->columns) {
1987 const struct ovsdb_column *column = node2->data;
1988
1989 if (column->persistent) {
1990 if (!columns) {
1991 columns = json_array_create_empty();
1992 }
1993 json_array_add(columns, json_string_create(column->name));
1994 }
1995 }
1996
1997 struct json *op = json_object_create();
1998 json_object_put_string(op, "op", "select");
1999 json_object_put_string(op, "table", table_name);
2000 json_object_put(op, "where", json_array_create_empty());
2001 json_object_put(op, "columns", columns);
2002 json_array_add(txn, op);
2003 }
2004
2005 /* Send request, get reply. */
2006 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
2007 struct jsonrpc_msg *reply;
2008 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
2009
2010 /* Print schema record. */
2011 print_and_free_log_record(ovsdb_schema_to_json(schema));
2012
2013 /* Print database transaction record. */
2014 if (reply->result->type != JSON_ARRAY
fa37affa 2015 || reply->result->array.n != shash_count(&schema->tables)) {
4d0a31b6
BP
2016 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
2017 shash_count(&schema->tables),
2018 json_to_string(reply->result, 0));
2019 }
2020 struct json *output_txn = json_object_create();
2021
2022 size_t i = 0;
2023 SHASH_FOR_EACH (node, &schema->tables) {
2024 const char *table_name = node->name;
2025 const struct ovsdb_table_schema *table = node->data;
fa37affa 2026 const struct json *op_result = reply->result->array.elems[i++];
4d0a31b6
BP
2027 struct json *rows;
2028
2029 if (op_result->type != JSON_OBJECT
2030 || !(rows = shash_find_data(json_object(op_result), "rows"))
2031 || rows->type != JSON_ARRAY) {
2032 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
2033 "member array: %s",
2034 table->name, json_to_string(op_result, 0));
2035 }
2036
fa37affa 2037 if (!rows->array.n) {
4d0a31b6
BP
2038 continue;
2039 }
2040
2041 struct json *output_rows = json_object_create();
fa37affa
BP
2042 for (size_t j = 0; j < rows->array.n; j++) {
2043 struct json *row = rows->array.elems[j];
4d0a31b6
BP
2044 if (row->type != JSON_OBJECT) {
2045 ovs_fatal(0, "%s table reply row is not an object: %s",
2046 table_name, json_to_string(row, 0));
2047 }
2048
2049 struct json *uuid_json = shash_find_and_delete(json_object(row),
2050 "_uuid");
2051 if (!uuid_json) {
2052 ovs_fatal(0, "%s table reply row lacks _uuid member: %s",
2053 table_name, json_to_string(row, 0));
2054 }
2055
2056 const struct ovsdb_base_type uuid_base = OVSDB_BASE_UUID_INIT;
2057 union ovsdb_atom atom;
2058 check_ovsdb_error(ovsdb_atom_from_json(&atom, &uuid_base,
2059 uuid_json, NULL));
2060
2061 char uuid_s[UUID_LEN + 1];
2062 snprintf(uuid_s, sizeof uuid_s, UUID_FMT, UUID_ARGS(&atom.uuid));
2063 json_object_put(output_rows, uuid_s, json_clone(row));
76c67e9a 2064 json_destroy(uuid_json);
4d0a31b6
BP
2065 }
2066 json_object_put(output_txn, table_name, output_rows);
2067 }
2068 output_txn = ovsdb_file_txn_annotate(
2069 output_txn, "produced by \"ovsdb-client backup\"");
2070 print_and_free_log_record(output_txn);
2071
2072 ovsdb_schema_destroy(schema);
2073 jsonrpc_msg_destroy(reply);
2074}
2075
1b1d2e6d
BP
2076static void
2077check_transaction_reply(struct jsonrpc_msg *reply)
2078{
2079 if (reply->result->type != JSON_ARRAY) {
2080 ovs_fatal(0, "result is not array");
2081 }
2082 for (size_t i = 0; i < json_array(reply->result)->n; i++) {
2083 struct json *json = json_array(reply->result)->elems[i];
2084 if (json->type != JSON_OBJECT) {
2085 ovs_fatal(0, "result array element is not object");
2086 }
2087 struct shash *object = json_object(json);
2088 if (shash_find(object, "error")) {
2089 ovs_fatal(0, "server returned error reply: %s",
2090 json_to_string(json, JSSF_SORT));
2091 }
2092 }
2093}
2094
fe0fb885
BP
2095static void
2096do_restore(struct jsonrpc *rpc, const char *database,
2097 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
2098{
2099 if (isatty(STDIN_FILENO)) {
2100 ovs_fatal(0, "not reading backup from a terminal; "
2101 "please redirect stdin from a file");
2102 }
cb8cbbbe 2103 set_binary_mode(stdin);
fe0fb885 2104
1b1d2e6d
BP
2105 struct ovsdb *backup = ovsdb_file_read("/dev/stdin", false);
2106 ovsdb_storage_close(backup->storage);
2107 backup->storage = NULL;
fe0fb885 2108
1b1d2e6d
BP
2109 struct ovsdb_schema *online_schema = fetch_schema(rpc, database);
2110 if (!ovsdb_schema_equal(backup->schema, online_schema)) {
fe0fb885 2111 struct ds s = DS_EMPTY_INITIALIZER;
1b1d2e6d 2112 if (strcmp(backup->schema->version, online_schema->version)) {
fe0fb885
BP
2113 ds_put_format(&s, "backup schema has version \"%s\" but "
2114 "database schema has version \"%s\"",
1b1d2e6d 2115 backup->schema->version, online_schema->version);
fe0fb885
BP
2116 } else {
2117 ds_put_format(&s, "backup schema and database schema are "
2118 "both version %s but still differ",
1b1d2e6d 2119 backup->schema->version);
fe0fb885
BP
2120 }
2121 if (!force) {
2122 ovs_fatal(0, "%s (use --force to override differences, or "
2123 "\"ovsdb-client convert\" to change the schema)",
2124 ds_cstr(&s));
2125 }
2126 VLOG_INFO("%s", ds_cstr(&s));
2127 ds_destroy(&s);
2128 }
1b1d2e6d 2129 ovsdb_schema_destroy(online_schema);
fe0fb885
BP
2130
2131 struct json *txn = json_array_create_empty();
1b1d2e6d 2132 json_array_add(txn, json_string_create(backup->schema->name));
fe0fb885
BP
2133 struct shash_node *node;
2134 SHASH_FOR_EACH (node, &backup->tables) {
2135 const char *table_name = node->name;
2136 struct ovsdb_table *table = node->data;
2137
2138 struct json *del_op = json_object_create();
2139 json_object_put_string(del_op, "op", "delete");
2140 json_object_put_string(del_op, "table", table_name);
2141 json_object_put(del_op, "where", json_array_create_empty());
2142 json_array_add(txn, del_op);
2143
2144 const struct ovsdb_row *row;
2145 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
2146 struct json *ins_op = json_object_create();
2147 json_object_put_string(ins_op, "op", "insert");
2148 json_object_put_string(ins_op, "table", table_name);
2149 json_object_put(ins_op, "uuid-name",
2150 json_string_create_nocopy(
2151 ovsdb_data_row_name(ovsdb_row_get_uuid(row))));
2152 struct json *row_json = json_object_create();
2153 json_object_put(ins_op, "row", row_json);
2154
2155 struct shash_node *node2;
2156 SHASH_FOR_EACH (node2, &table->schema->columns) {
2157 const struct ovsdb_column *column = node2->data;
2158 const struct ovsdb_datum *datum = &row->fields[column->index];
2159 const struct ovsdb_type *type = &column->type;
2160 if (column->persistent
2161 && column->index >= OVSDB_N_STD_COLUMNS
2162 && !ovsdb_datum_is_default(datum, type)) {
2163 struct json *value = ovsdb_datum_to_json_with_row_names(
2164 datum, type);
2165 json_object_put(row_json, column->name, value);
2166 }
2167 }
2168 json_array_add(txn, ins_op);
2169 }
2170 }
a34eba01 2171 ovsdb_destroy(backup);
fe0fb885
BP
2172 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
2173 struct jsonrpc_msg *reply;
2174 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
1b1d2e6d 2175 check_transaction_reply(reply);
fe0fb885
BP
2176 jsonrpc_msg_destroy(reply);
2177}
2178
2179
d0632593 2180static void
53ffefe9
BP
2181do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
2182 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593
BP
2183{
2184 usage();
2185}
2186
9aeba3f4
AZ
2187\f
2188/* "lock" command. */
2189
2190struct ovsdb_client_lock_req {
2191 const char *method;
2192 char *lock;
2193};
2194
2195static void
2196lock_req_init(struct ovsdb_client_lock_req *lock_req,
2197 const char *method, const char *lock_name)
2198{
2199 if (lock_req->method || lock_req->lock) {
2200 return;
2201 }
2202 lock_req->method = method;
2203 lock_req->lock = xstrdup(lock_name);
2204}
2205
2206static bool
2207lock_req_is_set(struct ovsdb_client_lock_req *lock_req)
2208{
2209 return lock_req->method;
2210}
2211
2212static void
2213lock_req_destroy(struct ovsdb_client_lock_req *lock_req)
2214{
2215 free(lock_req->lock);
2216 lock_req->method = NULL;
2217 lock_req->lock = NULL;
2218}
2219
2220/* Create a lock class request. Caller is responsible for free
2221 * the 'request' message. */
2222static struct jsonrpc_msg *
2223create_lock_request(struct ovsdb_client_lock_req *lock_req)
2224{
2225 struct json *locks, *lock;
2226
2227 locks = json_array_create_empty();
2228 lock = json_string_create(lock_req->lock);
2229 json_array_add(locks, lock);
2230
2231 return jsonrpc_create_request(lock_req->method, locks, NULL);
2232}
2233
2234static void
2235ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED,
2236 const char *argv[], void *lock_req_)
2237{
2238 struct ovsdb_client_lock_req *lock_req = lock_req_;
2239 lock_req_init(lock_req, "lock", argv[1]);
2240 unixctl_command_reply(conn, NULL);
2241}
2242
2243static void
2244ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED,
2245 const char *argv[], void *lock_req_)
2246{
2247 struct ovsdb_client_lock_req *lock_req = lock_req_;
2248 lock_req_init(lock_req, "unlock", argv[1]);
2249 unixctl_command_reply(conn, NULL);
2250}
2251
2252static void
2253ovsdb_client_steal(struct unixctl_conn *conn, int argc OVS_UNUSED,
2254 const char *argv[], void *lock_req_)
2255{
2256 struct ovsdb_client_lock_req *lock_req = lock_req_;
2257 lock_req_init(lock_req, "steal", argv[1]);
2258 unixctl_command_reply(conn, NULL);
2259}
2260
2261static void
2262do_lock(struct jsonrpc *rpc, const char *method, const char *lock)
2263{
2264 struct ovsdb_client_lock_req lock_req = {NULL, NULL};
2265 struct unixctl_server *unixctl;
2266 struct jsonrpc_msg *request;
2267 struct json *request_id = NULL;
2268 bool exiting = false;
2269 bool enable_lock_request = true; /* Don't send another request before
2270 getting a reply of the previous
2271 request. */
2272 daemon_save_fd(STDOUT_FILENO);
2273 daemonize_start(false);
2274 lock_req_init(&lock_req, method, lock);
2275
2276 if (get_detach()) {
2277 int error;
2278
2279 error = unixctl_server_create(NULL, &unixctl);
2280 if (error) {
2281 ovs_fatal(error, "failed to create unixctl server");
2282 }
2283
2284 unixctl_command_register("unlock", "LOCK", 1, 1,
2285 ovsdb_client_unlock, &lock_req);
2286 unixctl_command_register("steal", "LOCK", 1, 1,
2287 ovsdb_client_steal, &lock_req);
2288 unixctl_command_register("lock", "LOCK", 1, 1,
2289 ovsdb_client_lock, &lock_req);
2290 unixctl_command_register("exit", "", 0, 0,
2291 ovsdb_client_exit, &exiting);
2292 } else {
2293 unixctl = NULL;
2294 }
2295
2296 for (;;) {
2297 struct jsonrpc_msg *msg;
2298 int error;
2299
2300 unixctl_server_run(unixctl);
2301 if (enable_lock_request && lock_req_is_set(&lock_req)) {
2302 request = create_lock_request(&lock_req);
2303 request_id = json_clone(request->id);
2304 jsonrpc_send(rpc, request);
2305 lock_req_destroy(&lock_req);
2306 }
2307
2308 error = jsonrpc_recv(rpc, &msg);
2309 if (error == EAGAIN) {
2310 goto no_msg;
2311 } else if (error) {
2312 ovs_fatal(error, "%s: receive failed", jsonrpc_get_name(rpc));
2313 }
2314
2315 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
2316 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
2317 msg->id));
2318 } else if (msg->type == JSONRPC_REPLY
2319 && json_equal(msg->id, request_id)) {
2320 print_json(msg->result);
9aeba3f4
AZ
2321 fflush(stdout);
2322 enable_lock_request = true;
2323 json_destroy(request_id);
2324 request_id = NULL;
2325 daemonize_complete();
2326 } else if (msg->type == JSONRPC_NOTIFY) {
2327 puts(msg->method);
2328 print_json(msg->params);
9aeba3f4
AZ
2329 fflush(stdout);
2330 }
2331
2332 jsonrpc_msg_destroy(msg);
2333
2334no_msg:
2335 if (exiting) {
2336 break;
2337 }
2338
2339 jsonrpc_run(rpc);
2340 jsonrpc_wait(rpc);
2341 jsonrpc_recv_wait(rpc);
2342
2343 unixctl_server_wait(unixctl);
2344 poll_block();
2345 }
2346
2347 json_destroy(request_id);
2348 unixctl_server_destroy(unixctl);
2349}
2350
2351static void
2352do_lock_create(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2353 int argc OVS_UNUSED, char *argv[])
2354{
2355 do_lock(rpc, "lock", argv[0]);
2356}
2357
2358static void
2359do_lock_steal(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2360 int argc OVS_UNUSED, char *argv[])
2361{
2362 do_lock(rpc, "steal", argv[0]);
2363}
2364
2365static void
2366do_lock_unlock(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2367 int argc OVS_UNUSED, char *argv[])
2368{
2369 do_lock(rpc, "unlock", argv[0]);
2370}
2371
1b1d2e6d
BP
2372enum ovsdb_client_wait_type {
2373 WAIT_CONNECTED,
2374 WAIT_ADDED,
2375 WAIT_REMOVED
2376};
2377
2378static struct jsonrpc_msg *
2379compose_wait_transaction(enum ovsdb_client_wait_type type,
2380 const char *database)
2381{
2382 struct json *txn = json_array_create_empty();
2383 json_array_add(txn, json_string_create("_Server"));
2384
2385 struct json *op = json_object_create();
2386 json_array_add(txn, op);
2387 json_object_put_string(op, "op", "wait");
2388 json_object_put_string(op, "table", "Database");
2389 json_object_put(op, "where",
2390 json_array_create_1(
2391 json_array_create_3(
2392 json_string_create("name"),
2393 json_string_create("=="),
2394 json_string_create(database))));
2395
2396 if (type == WAIT_CONNECTED) {
2397 /* Wait until connected == true. */
2398 json_object_put(op, "columns",
2399 json_array_create_1(json_string_create("connected")));
2400 json_object_put_string(op, "until", "==");
2401
2402 struct json *row = json_object_create();
2403 json_object_put(row, "connected", json_boolean_create(true));
2404 json_object_put(op, "rows", json_array_create_1(row));
2405 } else {
2406 ovs_assert(type == WAIT_ADDED || type == WAIT_REMOVED);
2407
2408 /* Wait until such a row exists, or not, respectively. */
2409 json_object_put(op, "columns", json_array_create_empty());
2410 json_object_put_string(op, "until", "==");
2411 json_object_put(op, "rows",
2412 (type == WAIT_ADDED
2413 ? json_array_create_1(json_object_create())
2414 : json_array_create_empty()));
2415 }
2416 return jsonrpc_create_request("transact", txn, NULL);
2417}
2418
2419static void
2420do_wait(struct jsonrpc *rpc_unused OVS_UNUSED,
2421 const char *database_unused OVS_UNUSED,
2422 int argc, char *argv[])
2423{
1b1d2e6d
BP
2424 const char *database = argv[argc - 2];
2425 const char *state = argv[argc - 1];
2426
2427 enum ovsdb_client_wait_type type;
2428 if (!strcmp(state, "connected")) {
2429 type = WAIT_CONNECTED;
2430 } else if (!strcmp(state, "added")) {
2431 type = WAIT_ADDED;
2432 } else if (!strcmp(state, "removed")) {
2433 type = WAIT_REMOVED;
2434 } else {
2435 ovs_fatal(0, "%s: unknown state", state);
2436 }
2437
2438 char *remote = argc > 2 ? xstrdup(argv[0]) : default_remote();
2439 struct jsonrpc_session *js = jsonrpc_session_open(remote, true);
2440 free(remote);
2441
2442 unsigned int seqno = 0;
2443 struct json *sdca_id = NULL;
2444 struct json *txn_id = NULL;
2445 for (;;) {
2446 jsonrpc_session_run(js);
2447
2448 if (seqno != jsonrpc_session_get_seqno(js)
2449 && jsonrpc_session_is_connected(js)) {
2450 seqno = jsonrpc_session_get_seqno(js);
2451
2452 /* Send set_db_change_aware request. */
2453 struct jsonrpc_msg *rq = jsonrpc_create_request(
2454 "set_db_change_aware",
2455 json_array_create_1(json_boolean_create(true)),
2456 NULL);
2457 json_destroy(sdca_id);
2458 sdca_id = json_clone(rq->id);
2459 jsonrpc_session_send(js, rq);
2460
2461 /* Send transaction. */
2462 rq = compose_wait_transaction(type, database);
2463 json_destroy(txn_id);
2464 txn_id = json_clone(rq->id);
2465 jsonrpc_session_send(js, rq);
2466 }
2467
2468 struct jsonrpc_msg *reply = jsonrpc_session_recv(js);
2469 if (reply && reply->id) {
2470 if (sdca_id && json_equal(sdca_id, reply->id)) {
2471 if (reply->type == JSONRPC_ERROR) {
e7ea37ac 2472 ovs_error(0, "%s: set_db_change_aware failed (%s)",
1b1d2e6d
BP
2473 jsonrpc_session_get_name(js),
2474 json_to_string(reply->error, 0));
e7ea37ac
DS
2475 jsonrpc_msg_destroy(reply);
2476 exit(EXIT_FAILURE);
1b1d2e6d
BP
2477 }
2478 } else if (txn_id && json_equal(txn_id, reply->id)) {
2479 check_transaction_reply(reply);
e7ea37ac 2480 jsonrpc_msg_destroy(reply);
1b1d2e6d
BP
2481 exit(0);
2482 }
2483 }
2484 jsonrpc_msg_destroy(reply);
2485
2486 jsonrpc_session_recv_wait(js);
2487 jsonrpc_session_wait(js);
2488 poll_block();
2489 }
2490}
2491
2492/* Command handlers may take an optional server socket name (e.g. "unix:...")
2493 * and an optional database name (e.g. Open_vSwitch) as their initial
2494 * arguments. The NEED_* element indicates what a particular command needs.
2495 * These optional arguments should not be included in min_args or max_args, and
2496 * they are not included in the argc and argv arguments passed to the handler:
2497 * the argv[0] passed to the handler is the first argument after the optional
2498 * server socket name. */
53ffefe9
BP
2499static const struct ovsdb_client_command all_commands[] = {
2500 { "list-dbs", NEED_RPC, 0, 0, do_list_dbs },
2501 { "get-schema", NEED_DATABASE, 0, 0, do_get_schema },
2502 { "get-schema-version", NEED_DATABASE, 0, 0, do_get_schema_version },
33785c07 2503 { "get-schema-cksum", NEED_DATABASE, 0, 0, do_get_schema_cksum },
53ffefe9
BP
2504 { "list-tables", NEED_DATABASE, 0, 0, do_list_tables },
2505 { "list-columns", NEED_DATABASE, 0, 1, do_list_columns },
1b1d2e6d
BP
2506 { "transact", NEED_NONE, 1, 2, do_transact },
2507 { "query", NEED_NONE, 1, 2, do_query },
53ffefe9 2508 { "monitor", NEED_DATABASE, 1, INT_MAX, do_monitor },
c383f3bf 2509 { "monitor-cond", NEED_DATABASE, 2, 3, do_monitor_cond },
9167cb52 2510 { "monitor-cond-since", NEED_DATABASE, 2, 4, do_monitor_cond_since },
1b1d2e6d
BP
2511 { "wait", NEED_NONE, 2, 3, do_wait },
2512 { "convert", NEED_NONE, 1, 2, do_convert },
2513 { "needs-conversion", NEED_NONE, 1, 2, do_needs_conversion },
b30aa413 2514 { "dump", NEED_DATABASE, 0, INT_MAX, do_dump },
4d0a31b6 2515 { "backup", NEED_DATABASE, 0, 0, do_backup },
fe0fb885 2516 { "restore", NEED_DATABASE, 0, 0, do_restore },
9aeba3f4
AZ
2517 { "lock", NEED_RPC, 1, 1, do_lock_create },
2518 { "steal", NEED_RPC, 1, 1, do_lock_steal },
2519 { "unlock", NEED_RPC, 1, 1, do_lock_unlock },
53ffefe9
BP
2520 { "help", NEED_NONE, 0, INT_MAX, do_help },
2521
2522 { NULL, 0, 0, 0, NULL },
d0632593 2523};
3815d6c2
LS
2524
2525static const struct ovsdb_client_command *get_all_commands(void)
2526{
2527 return all_commands;
2528}