]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/ovsdb-client.c
ovsdb-server: drop all connections on read/write status change
[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);
1630 return !strcmp(parse_string_column(row, "model"), "clustered");
1631}
1632
53178986 1633static void
1b1d2e6d
BP
1634do_convert(struct jsonrpc *rpc, const char *database_ OVS_UNUSED,
1635 int argc, char *argv[])
53178986 1636{
1b1d2e6d 1637 const char *schema_file_name = argv[argc - 1];
53178986 1638 struct ovsdb_schema *new_schema;
1b1d2e6d
BP
1639 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &new_schema));
1640
1641 char *database = new_schema->name;
1642 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
1643
1644 if (is_database_clustered(rpc, database)) {
1645 ovsdb_schema_persist_ephemeral_columns(new_schema, schema_file_name);
1646 }
1647
1648 send_db_change_aware(rpc);
53178986
BP
1649
1650 struct jsonrpc_msg *request, *reply;
1651 request = jsonrpc_create_request(
1652 "convert",
1653 json_array_create_2(json_string_create(new_schema->name),
1654 ovsdb_schema_to_json(new_schema)), NULL);
1655 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
1656 jsonrpc_msg_destroy(reply);
1657}
1658
1659static void
1b1d2e6d 1660do_needs_conversion(struct jsonrpc *rpc, const char *database_ OVS_UNUSED,
53178986
BP
1661 int argc OVS_UNUSED, char *argv[])
1662{
1663 struct ovsdb_schema *schema1;
1664 check_ovsdb_error(ovsdb_schema_from_file(argv[0], &schema1));
1665
1b1d2e6d
BP
1666 char *database = schema1->name;
1667 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
1668
1669 if (is_database_clustered(rpc, database)) {
1670 ovsdb_schema_persist_ephemeral_columns(schema1, argv[0]);
1671 }
1672
53178986
BP
1673 struct ovsdb_schema *schema2 = fetch_schema(rpc, schema1->name);
1674 puts(ovsdb_schema_equal(schema1, schema2) ? "no" : "yes");
1675 ovsdb_schema_destroy(schema1);
1676 ovsdb_schema_destroy(schema2);
1677}
1678
25c269ef
BP
1679struct dump_table_aux {
1680 struct ovsdb_datum **data;
1681 const struct ovsdb_column **columns;
1682 size_t n_columns;
1683};
1684
1685static int
1686compare_data(size_t a_y, size_t b_y, size_t x,
1687 const struct dump_table_aux *aux)
1688{
1689 return ovsdb_datum_compare_3way(&aux->data[a_y][x],
1690 &aux->data[b_y][x],
1691 &aux->columns[x]->type);
1692}
1693
1694static int
1695compare_rows(size_t a_y, size_t b_y, void *aux_)
1696{
1697 struct dump_table_aux *aux = aux_;
1698 size_t x;
1699
1700 /* Skip UUID columns on the first pass, since their values tend to be
1701 * random and make our results less reproducible. */
1702 for (x = 0; x < aux->n_columns; x++) {
1703 if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
1704 int cmp = compare_data(a_y, b_y, x, aux);
1705 if (cmp) {
1706 return cmp;
1707 }
1708 }
1709 }
1710
1711 /* Use UUID columns as tie-breakers. */
1712 for (x = 0; x < aux->n_columns; x++) {
1713 if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
1714 int cmp = compare_data(a_y, b_y, x, aux);
1715 if (cmp) {
1716 return cmp;
1717 }
1718 }
1719 }
1720
1721 return 0;
1722}
1723
1724static void
1725swap_rows(size_t a_y, size_t b_y, void *aux_)
1726{
1727 struct dump_table_aux *aux = aux_;
1728 struct ovsdb_datum *tmp = aux->data[a_y];
1729 aux->data[a_y] = aux->data[b_y];
1730 aux->data[b_y] = tmp;
1731}
1732
25c269ef
BP
1733static int
1734compare_columns(const void *a_, const void *b_)
1735{
1736 const struct ovsdb_column *const *ap = a_;
1737 const struct ovsdb_column *const *bp = b_;
1738 const struct ovsdb_column *a = *ap;
1739 const struct ovsdb_column *b = *bp;
1740
1741 return strcmp(a->name, b->name);
1742}
1743
1744static void
b30aa413
BV
1745dump_table(const char *table_name, const struct shash *cols,
1746 struct json_array *rows)
25c269ef
BP
1747{
1748 const struct ovsdb_column **columns;
1749 size_t n_columns;
1750
1751 struct ovsdb_datum **data;
1752
1753 struct dump_table_aux aux;
1754 struct shash_node *node;
1755 struct table t;
1756 size_t x, y;
1757
1758 /* Sort columns by name, for reproducibility. */
b30aa413 1759 columns = xmalloc(shash_count(cols) * sizeof *columns);
25c269ef 1760 n_columns = 0;
b30aa413 1761 SHASH_FOR_EACH (node, cols) {
25c269ef
BP
1762 struct ovsdb_column *column = node->data;
1763 if (strcmp(column->name, "_version")) {
1764 columns[n_columns++] = column;
1765 }
1766 }
1767 qsort(columns, n_columns, sizeof *columns, compare_columns);
1768
1769 /* Extract data from table. */
1770 data = xmalloc(rows->n * sizeof *data);
1771 for (y = 0; y < rows->n; y++) {
1772 struct shash *row;
1773
1774 if (rows->elems[y]->type != JSON_OBJECT) {
34582733 1775 ovs_fatal(0, "row %"PRIuSIZE" in table %s response is not a JSON object: "
b30aa413 1776 "%s", y, table_name, json_to_string(rows->elems[y], 0));
25c269ef
BP
1777 }
1778 row = json_object(rows->elems[y]);
1779
1780 data[y] = xmalloc(n_columns * sizeof **data);
1781 for (x = 0; x < n_columns; x++) {
1782 const struct json *json = shash_find_data(row, columns[x]->name);
1783 if (!json) {
34582733 1784 ovs_fatal(0, "row %"PRIuSIZE" in table %s response lacks %s column",
b30aa413 1785 y, table_name, columns[x]->name);
25c269ef
BP
1786 }
1787
9041097a
BP
1788 check_ovsdb_error(ovsdb_unconstrained_datum_from_json(
1789 &data[y][x], &columns[x]->type, json));
25c269ef
BP
1790 }
1791 }
1792
1793 /* Sort rows by column values, for reproducibility. */
1794 aux.data = data;
1795 aux.columns = columns;
1796 aux.n_columns = n_columns;
1797 sort(rows->n, compare_rows, swap_rows, &aux);
1798
1799 /* Add column headings. */
1800 table_init(&t);
b30aa413 1801 table_set_caption(&t, xasprintf("%s table", table_name));
25c269ef
BP
1802 for (x = 0; x < n_columns; x++) {
1803 table_add_column(&t, "%s", columns[x]->name);
1804 }
1805
1806 /* Print rows. */
1807 for (y = 0; y < rows->n; y++) {
1808 table_add_row(&t);
1809 for (x = 0; x < n_columns; x++) {
772387d5
BP
1810 struct cell *cell = table_add_cell(&t);
1811 cell->json = ovsdb_datum_to_json(&data[y][x], &columns[x]->type);
1812 cell->type = &columns[x]->type;
e49190c4 1813 ovsdb_datum_destroy(&data[y][x], &columns[x]->type);
25c269ef 1814 }
e49190c4 1815 free(data[y]);
25c269ef 1816 }
3a3eb9da 1817 table_print(&t, &table_style);
25c269ef 1818 table_destroy(&t);
e49190c4
BP
1819
1820 free(data);
1821 free(columns);
25c269ef
BP
1822}
1823
1824static void
53ffefe9 1825do_dump(struct jsonrpc *rpc, const char *database,
b30aa413 1826 int argc, char *argv[])
25c269ef 1827{
25c269ef
BP
1828 struct jsonrpc_msg *request, *reply;
1829 struct ovsdb_schema *schema;
1830 struct json *transaction;
25c269ef 1831
b30aa413 1832 const struct shash_node *node, **tables;
25c269ef 1833 size_t n_tables;
b30aa413
BV
1834 struct ovsdb_table_schema *tschema;
1835 const struct shash *columns;
1836 struct shash custom_columns;
25c269ef
BP
1837
1838 size_t i;
1839
b30aa413 1840 shash_init(&custom_columns);
53ffefe9 1841 schema = fetch_schema(rpc, database);
b30aa413
BV
1842 if (argc) {
1843 node = shash_find(&schema->tables, argv[0]);
1844 if (!node) {
1845 ovs_fatal(0, "No table \"%s\" found.", argv[0]);
1846 }
2b03ef95 1847 tables = xmemdup(&node, sizeof node);
b30aa413
BV
1848 n_tables = 1;
1849 tschema = tables[0]->data;
1850 for (i = 1; i < argc; i++) {
1851 node = shash_find(&tschema->columns, argv[i]);
1852 if (!node) {
0d5450a2 1853 ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[i]);
b30aa413 1854 }
0d5450a2 1855 shash_add(&custom_columns, argv[i], node->data);
b30aa413
BV
1856 }
1857 } else {
1858 tables = shash_sort(&schema->tables);
1859 n_tables = shash_count(&schema->tables);
1860 }
25c269ef
BP
1861
1862 /* Construct transaction to retrieve entire database. */
1863 transaction = json_array_create_1(json_string_create(database));
1864 for (i = 0; i < n_tables; i++) {
1865 const struct ovsdb_table_schema *ts = tables[i]->data;
b30aa413 1866 struct json *op, *jcolumns;
25c269ef 1867
b30aa413
BV
1868 if (argc > 1) {
1869 columns = &custom_columns;
1870 } else {
1871 columns = &ts->columns;
1872 }
1873 jcolumns = json_array_create_empty();
1874 SHASH_FOR_EACH (node, columns) {
25c269ef
BP
1875 const struct ovsdb_column *column = node->data;
1876
1877 if (strcmp(column->name, "_version")) {
b30aa413 1878 json_array_add(jcolumns, json_string_create(column->name));
25c269ef
BP
1879 }
1880 }
1881
1882 op = json_object_create();
1883 json_object_put_string(op, "op", "select");
1884 json_object_put_string(op, "table", tables[i]->name);
1885 json_object_put(op, "where", json_array_create_empty());
b30aa413 1886 json_object_put(op, "columns", jcolumns);
25c269ef
BP
1887 json_array_add(transaction, op);
1888 }
1889
1890 /* Send request, get reply. */
1891 request = jsonrpc_create_request("transact", transaction, NULL);
d35f8e72 1892 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
25c269ef
BP
1893
1894 /* Print database contents. */
1895 if (reply->result->type != JSON_ARRAY
fa37affa 1896 || reply->result->array.n != n_tables) {
34582733 1897 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
25c269ef
BP
1898 n_tables, json_to_string(reply->result, 0));
1899 }
1900 for (i = 0; i < n_tables; i++) {
1901 const struct ovsdb_table_schema *ts = tables[i]->data;
fa37affa 1902 const struct json *op_result = reply->result->array.elems[i];
25c269ef
BP
1903 struct json *rows;
1904
1905 if (op_result->type != JSON_OBJECT
1906 || !(rows = shash_find_data(json_object(op_result), "rows"))
1907 || rows->type != JSON_ARRAY) {
1908 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1909 "member array: %s",
1910 ts->name, json_to_string(op_result, 0));
1911 }
1912
b30aa413 1913 if (argc > 1) {
fa37affa 1914 dump_table(tables[i]->name, &custom_columns, &rows->array);
b30aa413 1915 } else {
fa37affa 1916 dump_table(tables[i]->name, &ts->columns, &rows->array);
b30aa413 1917 }
25c269ef 1918 }
e49190c4
BP
1919
1920 jsonrpc_msg_destroy(reply);
b30aa413 1921 shash_destroy(&custom_columns);
e49190c4
BP
1922 free(tables);
1923 ovsdb_schema_destroy(schema);
25c269ef
BP
1924}
1925
4d0a31b6
BP
1926static void
1927print_and_free_log_record(struct json *record)
1928{
1929 struct ds header = DS_EMPTY_INITIALIZER;
1930 struct ds data = DS_EMPTY_INITIALIZER;
19b276cb 1931 ovsdb_log_compose_record(record, OVSDB_MAGIC, &header, &data);
4d0a31b6
BP
1932 fwrite(header.string, header.length, 1, stdout);
1933 fwrite(data.string, data.length, 1, stdout);
1934 ds_destroy(&data);
1935 ds_destroy(&header);
1936 json_destroy(record);
1937}
1938
cb8cbbbe
AGS
1939static void
1940set_binary_mode(FILE *stream OVS_UNUSED)
1941{
1942#ifdef _WIN32
1943 fflush(stream);
1944 /* On Windows set binary mode on the file descriptor to avoid
1945 * translation (i.e. CRLF line endings). */
1946 if (_setmode(_fileno(stream), O_BINARY) == -1) {
1947 ovs_fatal(errno, "could not set binary mode on fd %d",
1948 _fileno(stream));
1949 }
1950#endif
1951}
1952
4d0a31b6
BP
1953static void
1954do_backup(struct jsonrpc *rpc, const char *database,
1955 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1956{
1957 if (isatty(STDOUT_FILENO)) {
1958 ovs_fatal(0, "not writing backup to a terminal; "
1959 "please redirect stdout to a file");
1960 }
cb8cbbbe 1961 set_binary_mode(stdout);
4d0a31b6
BP
1962
1963 /* Get schema. */
1964 struct ovsdb_schema *schema = fetch_schema(rpc, database);
1965
1966 /* Construct transaction to retrieve all tables. */
1967 struct json *txn = json_array_create_1(json_string_create(database));
1968 struct shash_node *node;
1969 SHASH_FOR_EACH (node, &schema->tables) {
1970 const char *table_name = node->name;
1971 const struct ovsdb_table_schema *table = node->data;
1972
1973 /* Get all the columns except _version and the ephemeral ones.
1974 *
1975 * We don't omit tables that only have ephemeral columns because of the
1976 * possibility that other tables references rows in those tables; that
1977 * is, even if all the columns are ephemeral, the rows themselves are
1978 * not. */
1979 struct json *columns = json_array_create_empty();
1980 struct shash_node *node2;
1981 SHASH_FOR_EACH (node2, &table->columns) {
1982 const struct ovsdb_column *column = node2->data;
1983
1984 if (column->persistent) {
1985 if (!columns) {
1986 columns = json_array_create_empty();
1987 }
1988 json_array_add(columns, json_string_create(column->name));
1989 }
1990 }
1991
1992 struct json *op = json_object_create();
1993 json_object_put_string(op, "op", "select");
1994 json_object_put_string(op, "table", table_name);
1995 json_object_put(op, "where", json_array_create_empty());
1996 json_object_put(op, "columns", columns);
1997 json_array_add(txn, op);
1998 }
1999
2000 /* Send request, get reply. */
2001 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
2002 struct jsonrpc_msg *reply;
2003 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
2004
2005 /* Print schema record. */
2006 print_and_free_log_record(ovsdb_schema_to_json(schema));
2007
2008 /* Print database transaction record. */
2009 if (reply->result->type != JSON_ARRAY
fa37affa 2010 || reply->result->array.n != shash_count(&schema->tables)) {
4d0a31b6
BP
2011 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
2012 shash_count(&schema->tables),
2013 json_to_string(reply->result, 0));
2014 }
2015 struct json *output_txn = json_object_create();
2016
2017 size_t i = 0;
2018 SHASH_FOR_EACH (node, &schema->tables) {
2019 const char *table_name = node->name;
2020 const struct ovsdb_table_schema *table = node->data;
fa37affa 2021 const struct json *op_result = reply->result->array.elems[i++];
4d0a31b6
BP
2022 struct json *rows;
2023
2024 if (op_result->type != JSON_OBJECT
2025 || !(rows = shash_find_data(json_object(op_result), "rows"))
2026 || rows->type != JSON_ARRAY) {
2027 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
2028 "member array: %s",
2029 table->name, json_to_string(op_result, 0));
2030 }
2031
fa37affa 2032 if (!rows->array.n) {
4d0a31b6
BP
2033 continue;
2034 }
2035
2036 struct json *output_rows = json_object_create();
fa37affa
BP
2037 for (size_t j = 0; j < rows->array.n; j++) {
2038 struct json *row = rows->array.elems[j];
4d0a31b6
BP
2039 if (row->type != JSON_OBJECT) {
2040 ovs_fatal(0, "%s table reply row is not an object: %s",
2041 table_name, json_to_string(row, 0));
2042 }
2043
2044 struct json *uuid_json = shash_find_and_delete(json_object(row),
2045 "_uuid");
2046 if (!uuid_json) {
2047 ovs_fatal(0, "%s table reply row lacks _uuid member: %s",
2048 table_name, json_to_string(row, 0));
2049 }
2050
2051 const struct ovsdb_base_type uuid_base = OVSDB_BASE_UUID_INIT;
2052 union ovsdb_atom atom;
2053 check_ovsdb_error(ovsdb_atom_from_json(&atom, &uuid_base,
2054 uuid_json, NULL));
2055
2056 char uuid_s[UUID_LEN + 1];
2057 snprintf(uuid_s, sizeof uuid_s, UUID_FMT, UUID_ARGS(&atom.uuid));
2058 json_object_put(output_rows, uuid_s, json_clone(row));
2059 }
2060 json_object_put(output_txn, table_name, output_rows);
2061 }
2062 output_txn = ovsdb_file_txn_annotate(
2063 output_txn, "produced by \"ovsdb-client backup\"");
2064 print_and_free_log_record(output_txn);
2065
2066 ovsdb_schema_destroy(schema);
2067 jsonrpc_msg_destroy(reply);
2068}
2069
1b1d2e6d
BP
2070static void
2071check_transaction_reply(struct jsonrpc_msg *reply)
2072{
2073 if (reply->result->type != JSON_ARRAY) {
2074 ovs_fatal(0, "result is not array");
2075 }
2076 for (size_t i = 0; i < json_array(reply->result)->n; i++) {
2077 struct json *json = json_array(reply->result)->elems[i];
2078 if (json->type != JSON_OBJECT) {
2079 ovs_fatal(0, "result array element is not object");
2080 }
2081 struct shash *object = json_object(json);
2082 if (shash_find(object, "error")) {
2083 ovs_fatal(0, "server returned error reply: %s",
2084 json_to_string(json, JSSF_SORT));
2085 }
2086 }
2087}
2088
fe0fb885
BP
2089static void
2090do_restore(struct jsonrpc *rpc, const char *database,
2091 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
2092{
2093 if (isatty(STDIN_FILENO)) {
2094 ovs_fatal(0, "not reading backup from a terminal; "
2095 "please redirect stdin from a file");
2096 }
cb8cbbbe 2097 set_binary_mode(stdin);
fe0fb885 2098
1b1d2e6d
BP
2099 struct ovsdb *backup = ovsdb_file_read("/dev/stdin", false);
2100 ovsdb_storage_close(backup->storage);
2101 backup->storage = NULL;
fe0fb885 2102
1b1d2e6d
BP
2103 struct ovsdb_schema *online_schema = fetch_schema(rpc, database);
2104 if (!ovsdb_schema_equal(backup->schema, online_schema)) {
fe0fb885 2105 struct ds s = DS_EMPTY_INITIALIZER;
1b1d2e6d 2106 if (strcmp(backup->schema->version, online_schema->version)) {
fe0fb885
BP
2107 ds_put_format(&s, "backup schema has version \"%s\" but "
2108 "database schema has version \"%s\"",
1b1d2e6d 2109 backup->schema->version, online_schema->version);
fe0fb885
BP
2110 } else {
2111 ds_put_format(&s, "backup schema and database schema are "
2112 "both version %s but still differ",
1b1d2e6d 2113 backup->schema->version);
fe0fb885
BP
2114 }
2115 if (!force) {
2116 ovs_fatal(0, "%s (use --force to override differences, or "
2117 "\"ovsdb-client convert\" to change the schema)",
2118 ds_cstr(&s));
2119 }
2120 VLOG_INFO("%s", ds_cstr(&s));
2121 ds_destroy(&s);
2122 }
1b1d2e6d 2123 ovsdb_schema_destroy(online_schema);
fe0fb885
BP
2124
2125 struct json *txn = json_array_create_empty();
1b1d2e6d 2126 json_array_add(txn, json_string_create(backup->schema->name));
fe0fb885
BP
2127 struct shash_node *node;
2128 SHASH_FOR_EACH (node, &backup->tables) {
2129 const char *table_name = node->name;
2130 struct ovsdb_table *table = node->data;
2131
2132 struct json *del_op = json_object_create();
2133 json_object_put_string(del_op, "op", "delete");
2134 json_object_put_string(del_op, "table", table_name);
2135 json_object_put(del_op, "where", json_array_create_empty());
2136 json_array_add(txn, del_op);
2137
2138 const struct ovsdb_row *row;
2139 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
2140 struct json *ins_op = json_object_create();
2141 json_object_put_string(ins_op, "op", "insert");
2142 json_object_put_string(ins_op, "table", table_name);
2143 json_object_put(ins_op, "uuid-name",
2144 json_string_create_nocopy(
2145 ovsdb_data_row_name(ovsdb_row_get_uuid(row))));
2146 struct json *row_json = json_object_create();
2147 json_object_put(ins_op, "row", row_json);
2148
2149 struct shash_node *node2;
2150 SHASH_FOR_EACH (node2, &table->schema->columns) {
2151 const struct ovsdb_column *column = node2->data;
2152 const struct ovsdb_datum *datum = &row->fields[column->index];
2153 const struct ovsdb_type *type = &column->type;
2154 if (column->persistent
2155 && column->index >= OVSDB_N_STD_COLUMNS
2156 && !ovsdb_datum_is_default(datum, type)) {
2157 struct json *value = ovsdb_datum_to_json_with_row_names(
2158 datum, type);
2159 json_object_put(row_json, column->name, value);
2160 }
2161 }
2162 json_array_add(txn, ins_op);
2163 }
2164 }
a34eba01 2165 ovsdb_destroy(backup);
fe0fb885
BP
2166 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
2167 struct jsonrpc_msg *reply;
2168 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
1b1d2e6d 2169 check_transaction_reply(reply);
fe0fb885
BP
2170 jsonrpc_msg_destroy(reply);
2171}
2172
2173
d0632593 2174static void
53ffefe9
BP
2175do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
2176 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593
BP
2177{
2178 usage();
2179}
2180
9aeba3f4
AZ
2181\f
2182/* "lock" command. */
2183
2184struct ovsdb_client_lock_req {
2185 const char *method;
2186 char *lock;
2187};
2188
2189static void
2190lock_req_init(struct ovsdb_client_lock_req *lock_req,
2191 const char *method, const char *lock_name)
2192{
2193 if (lock_req->method || lock_req->lock) {
2194 return;
2195 }
2196 lock_req->method = method;
2197 lock_req->lock = xstrdup(lock_name);
2198}
2199
2200static bool
2201lock_req_is_set(struct ovsdb_client_lock_req *lock_req)
2202{
2203 return lock_req->method;
2204}
2205
2206static void
2207lock_req_destroy(struct ovsdb_client_lock_req *lock_req)
2208{
2209 free(lock_req->lock);
2210 lock_req->method = NULL;
2211 lock_req->lock = NULL;
2212}
2213
2214/* Create a lock class request. Caller is responsible for free
2215 * the 'request' message. */
2216static struct jsonrpc_msg *
2217create_lock_request(struct ovsdb_client_lock_req *lock_req)
2218{
2219 struct json *locks, *lock;
2220
2221 locks = json_array_create_empty();
2222 lock = json_string_create(lock_req->lock);
2223 json_array_add(locks, lock);
2224
2225 return jsonrpc_create_request(lock_req->method, locks, NULL);
2226}
2227
2228static void
2229ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED,
2230 const char *argv[], void *lock_req_)
2231{
2232 struct ovsdb_client_lock_req *lock_req = lock_req_;
2233 lock_req_init(lock_req, "lock", argv[1]);
2234 unixctl_command_reply(conn, NULL);
2235}
2236
2237static void
2238ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED,
2239 const char *argv[], void *lock_req_)
2240{
2241 struct ovsdb_client_lock_req *lock_req = lock_req_;
2242 lock_req_init(lock_req, "unlock", argv[1]);
2243 unixctl_command_reply(conn, NULL);
2244}
2245
2246static void
2247ovsdb_client_steal(struct unixctl_conn *conn, int argc OVS_UNUSED,
2248 const char *argv[], void *lock_req_)
2249{
2250 struct ovsdb_client_lock_req *lock_req = lock_req_;
2251 lock_req_init(lock_req, "steal", argv[1]);
2252 unixctl_command_reply(conn, NULL);
2253}
2254
2255static void
2256do_lock(struct jsonrpc *rpc, const char *method, const char *lock)
2257{
2258 struct ovsdb_client_lock_req lock_req = {NULL, NULL};
2259 struct unixctl_server *unixctl;
2260 struct jsonrpc_msg *request;
2261 struct json *request_id = NULL;
2262 bool exiting = false;
2263 bool enable_lock_request = true; /* Don't send another request before
2264 getting a reply of the previous
2265 request. */
2266 daemon_save_fd(STDOUT_FILENO);
2267 daemonize_start(false);
2268 lock_req_init(&lock_req, method, lock);
2269
2270 if (get_detach()) {
2271 int error;
2272
2273 error = unixctl_server_create(NULL, &unixctl);
2274 if (error) {
2275 ovs_fatal(error, "failed to create unixctl server");
2276 }
2277
2278 unixctl_command_register("unlock", "LOCK", 1, 1,
2279 ovsdb_client_unlock, &lock_req);
2280 unixctl_command_register("steal", "LOCK", 1, 1,
2281 ovsdb_client_steal, &lock_req);
2282 unixctl_command_register("lock", "LOCK", 1, 1,
2283 ovsdb_client_lock, &lock_req);
2284 unixctl_command_register("exit", "", 0, 0,
2285 ovsdb_client_exit, &exiting);
2286 } else {
2287 unixctl = NULL;
2288 }
2289
2290 for (;;) {
2291 struct jsonrpc_msg *msg;
2292 int error;
2293
2294 unixctl_server_run(unixctl);
2295 if (enable_lock_request && lock_req_is_set(&lock_req)) {
2296 request = create_lock_request(&lock_req);
2297 request_id = json_clone(request->id);
2298 jsonrpc_send(rpc, request);
2299 lock_req_destroy(&lock_req);
2300 }
2301
2302 error = jsonrpc_recv(rpc, &msg);
2303 if (error == EAGAIN) {
2304 goto no_msg;
2305 } else if (error) {
2306 ovs_fatal(error, "%s: receive failed", jsonrpc_get_name(rpc));
2307 }
2308
2309 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
2310 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
2311 msg->id));
2312 } else if (msg->type == JSONRPC_REPLY
2313 && json_equal(msg->id, request_id)) {
2314 print_json(msg->result);
9aeba3f4
AZ
2315 fflush(stdout);
2316 enable_lock_request = true;
2317 json_destroy(request_id);
2318 request_id = NULL;
2319 daemonize_complete();
2320 } else if (msg->type == JSONRPC_NOTIFY) {
2321 puts(msg->method);
2322 print_json(msg->params);
9aeba3f4
AZ
2323 fflush(stdout);
2324 }
2325
2326 jsonrpc_msg_destroy(msg);
2327
2328no_msg:
2329 if (exiting) {
2330 break;
2331 }
2332
2333 jsonrpc_run(rpc);
2334 jsonrpc_wait(rpc);
2335 jsonrpc_recv_wait(rpc);
2336
2337 unixctl_server_wait(unixctl);
2338 poll_block();
2339 }
2340
2341 json_destroy(request_id);
2342 unixctl_server_destroy(unixctl);
2343}
2344
2345static void
2346do_lock_create(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2347 int argc OVS_UNUSED, char *argv[])
2348{
2349 do_lock(rpc, "lock", argv[0]);
2350}
2351
2352static void
2353do_lock_steal(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2354 int argc OVS_UNUSED, char *argv[])
2355{
2356 do_lock(rpc, "steal", argv[0]);
2357}
2358
2359static void
2360do_lock_unlock(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2361 int argc OVS_UNUSED, char *argv[])
2362{
2363 do_lock(rpc, "unlock", argv[0]);
2364}
2365
1b1d2e6d
BP
2366enum ovsdb_client_wait_type {
2367 WAIT_CONNECTED,
2368 WAIT_ADDED,
2369 WAIT_REMOVED
2370};
2371
2372static struct jsonrpc_msg *
2373compose_wait_transaction(enum ovsdb_client_wait_type type,
2374 const char *database)
2375{
2376 struct json *txn = json_array_create_empty();
2377 json_array_add(txn, json_string_create("_Server"));
2378
2379 struct json *op = json_object_create();
2380 json_array_add(txn, op);
2381 json_object_put_string(op, "op", "wait");
2382 json_object_put_string(op, "table", "Database");
2383 json_object_put(op, "where",
2384 json_array_create_1(
2385 json_array_create_3(
2386 json_string_create("name"),
2387 json_string_create("=="),
2388 json_string_create(database))));
2389
2390 if (type == WAIT_CONNECTED) {
2391 /* Wait until connected == true. */
2392 json_object_put(op, "columns",
2393 json_array_create_1(json_string_create("connected")));
2394 json_object_put_string(op, "until", "==");
2395
2396 struct json *row = json_object_create();
2397 json_object_put(row, "connected", json_boolean_create(true));
2398 json_object_put(op, "rows", json_array_create_1(row));
2399 } else {
2400 ovs_assert(type == WAIT_ADDED || type == WAIT_REMOVED);
2401
2402 /* Wait until such a row exists, or not, respectively. */
2403 json_object_put(op, "columns", json_array_create_empty());
2404 json_object_put_string(op, "until", "==");
2405 json_object_put(op, "rows",
2406 (type == WAIT_ADDED
2407 ? json_array_create_1(json_object_create())
2408 : json_array_create_empty()));
2409 }
2410 return jsonrpc_create_request("transact", txn, NULL);
2411}
2412
2413static void
2414do_wait(struct jsonrpc *rpc_unused OVS_UNUSED,
2415 const char *database_unused OVS_UNUSED,
2416 int argc, char *argv[])
2417{
1b1d2e6d
BP
2418 const char *database = argv[argc - 2];
2419 const char *state = argv[argc - 1];
2420
2421 enum ovsdb_client_wait_type type;
2422 if (!strcmp(state, "connected")) {
2423 type = WAIT_CONNECTED;
2424 } else if (!strcmp(state, "added")) {
2425 type = WAIT_ADDED;
2426 } else if (!strcmp(state, "removed")) {
2427 type = WAIT_REMOVED;
2428 } else {
2429 ovs_fatal(0, "%s: unknown state", state);
2430 }
2431
2432 char *remote = argc > 2 ? xstrdup(argv[0]) : default_remote();
2433 struct jsonrpc_session *js = jsonrpc_session_open(remote, true);
2434 free(remote);
2435
2436 unsigned int seqno = 0;
2437 struct json *sdca_id = NULL;
2438 struct json *txn_id = NULL;
2439 for (;;) {
2440 jsonrpc_session_run(js);
2441
2442 if (seqno != jsonrpc_session_get_seqno(js)
2443 && jsonrpc_session_is_connected(js)) {
2444 seqno = jsonrpc_session_get_seqno(js);
2445
2446 /* Send set_db_change_aware request. */
2447 struct jsonrpc_msg *rq = jsonrpc_create_request(
2448 "set_db_change_aware",
2449 json_array_create_1(json_boolean_create(true)),
2450 NULL);
2451 json_destroy(sdca_id);
2452 sdca_id = json_clone(rq->id);
2453 jsonrpc_session_send(js, rq);
2454
2455 /* Send transaction. */
2456 rq = compose_wait_transaction(type, database);
2457 json_destroy(txn_id);
2458 txn_id = json_clone(rq->id);
2459 jsonrpc_session_send(js, rq);
2460 }
2461
2462 struct jsonrpc_msg *reply = jsonrpc_session_recv(js);
2463 if (reply && reply->id) {
2464 if (sdca_id && json_equal(sdca_id, reply->id)) {
2465 if (reply->type == JSONRPC_ERROR) {
2466 ovs_fatal(0, "%s: set_db_change_aware failed (%s)",
2467 jsonrpc_session_get_name(js),
2468 json_to_string(reply->error, 0));
2469 }
2470 } else if (txn_id && json_equal(txn_id, reply->id)) {
2471 check_transaction_reply(reply);
2472 exit(0);
2473 }
2474 }
2475 jsonrpc_msg_destroy(reply);
2476
2477 jsonrpc_session_recv_wait(js);
2478 jsonrpc_session_wait(js);
2479 poll_block();
2480 }
2481}
2482
2483/* Command handlers may take an optional server socket name (e.g. "unix:...")
2484 * and an optional database name (e.g. Open_vSwitch) as their initial
2485 * arguments. The NEED_* element indicates what a particular command needs.
2486 * These optional arguments should not be included in min_args or max_args, and
2487 * they are not included in the argc and argv arguments passed to the handler:
2488 * the argv[0] passed to the handler is the first argument after the optional
2489 * server socket name. */
53ffefe9
BP
2490static const struct ovsdb_client_command all_commands[] = {
2491 { "list-dbs", NEED_RPC, 0, 0, do_list_dbs },
2492 { "get-schema", NEED_DATABASE, 0, 0, do_get_schema },
2493 { "get-schema-version", NEED_DATABASE, 0, 0, do_get_schema_version },
33785c07 2494 { "get-schema-cksum", NEED_DATABASE, 0, 0, do_get_schema_cksum },
53ffefe9
BP
2495 { "list-tables", NEED_DATABASE, 0, 0, do_list_tables },
2496 { "list-columns", NEED_DATABASE, 0, 1, do_list_columns },
1b1d2e6d
BP
2497 { "transact", NEED_NONE, 1, 2, do_transact },
2498 { "query", NEED_NONE, 1, 2, do_query },
53ffefe9 2499 { "monitor", NEED_DATABASE, 1, INT_MAX, do_monitor },
c383f3bf 2500 { "monitor-cond", NEED_DATABASE, 2, 3, do_monitor_cond },
9167cb52 2501 { "monitor-cond-since", NEED_DATABASE, 2, 4, do_monitor_cond_since },
1b1d2e6d
BP
2502 { "wait", NEED_NONE, 2, 3, do_wait },
2503 { "convert", NEED_NONE, 1, 2, do_convert },
2504 { "needs-conversion", NEED_NONE, 1, 2, do_needs_conversion },
b30aa413 2505 { "dump", NEED_DATABASE, 0, INT_MAX, do_dump },
4d0a31b6 2506 { "backup", NEED_DATABASE, 0, 0, do_backup },
fe0fb885 2507 { "restore", NEED_DATABASE, 0, 0, do_restore },
9aeba3f4
AZ
2508 { "lock", NEED_RPC, 1, 1, do_lock_create },
2509 { "steal", NEED_RPC, 1, 1, do_lock_steal },
2510 { "unlock", NEED_RPC, 1, 1, do_lock_unlock },
53ffefe9
BP
2511 { "help", NEED_NONE, 0, INT_MAX, do_help },
2512
2513 { NULL, 0, 0, 0, NULL },
d0632593 2514};
3815d6c2
LS
2515
2516static const struct ovsdb_client_command *get_all_commands(void)
2517{
2518 return all_commands;
2519}