]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/ovsdb-client.c
ovsdb_monitor: Fix style of prototypes.
[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"
53178986
BP
433 "\n convert [SERVER] SCHEMA\n"
434 " convert database on SERVER named in SCHEMA to SCHEMA.\n"
435 "\n needs-conversion [SERVER] SCHEMA\n"
436 " tests whether SCHEMA's db on SERVER needs conversion.\n"
4227b221
BP
437 "\n monitor [SERVER] [DATABASE] ALL\n"
438 " monitor all changes to all columns in all tables\n"
1b1d2e6d
BP
439 "\n wait [SERVER] DATABASE STATE\n"
440 " wait until DATABASE reaches STATE "
441 "(\"added\" or \"connected\" or \"removed\")\n"
4227b221 442 " in DATBASE on SERVER.\n"
85226894 443 "\n dump [SERVER] [DATABASE]\n"
53ffefe9 444 " dump contents of DATABASE on SERVER to stdout\n"
fe0fb885 445 "\n backup [SERVER] [DATABASE] > SNAPSHOT\n"
4d0a31b6 446 " dump database contents in the form of a database file\n"
fe0fb885
BP
447 "\n [--force] restore [SERVER] [DATABASE] < SNAPSHOT\n"
448 " restore database contents from a database file\n"
9aeba3f4
AZ
449 "\n lock [SERVER] LOCK\n"
450 " create or wait for LOCK in SERVER\n"
451 "\n steal [SERVER] LOCK\n"
452 " steal LOCK from SERVER\n"
453 "\n unlock [SERVER] LOCK\n"
454 " unlock LOCK from SERVER\n"
53ffefe9
BP
455 "\nThe default SERVER is unix:%s/db.sock.\n"
456 "The default DATABASE is Open_vSwitch.\n",
457 program_name, program_name, ovs_rundir());
9467fe62 458 stream_usage("SERVER", true, true, true);
bcb58ce0
LR
459 table_usage();
460 printf(" --timestamp timestamp \"monitor\" output");
3f262d7d 461 daemon_usage();
d0632593
BP
462 vlog_usage();
463 printf("\nOther options:\n"
464 " -h, --help display this help message\n"
465 " -V, --version display version information\n");
466 exit(EXIT_SUCCESS);
467}
468\f
d35f8e72
EJ
469static void
470check_txn(int error, struct jsonrpc_msg **reply_)
471{
472 struct jsonrpc_msg *reply = *reply_;
473
474 if (error) {
475 ovs_fatal(error, "transaction failed");
476 }
477
478 if (reply->error) {
479 ovs_fatal(error, "transaction returned error: %s",
480 json_to_string(reply->error, table_style.json_flags));
481 }
482}
483
6d65eee8
BP
484static struct json *
485parse_json(const char *s)
486{
487 struct json *json = json_from_string(s);
488 if (json->type == JSON_STRING) {
fa37affa 489 ovs_fatal(0, "\"%s\": %s", s, json->string);
6d65eee8
BP
490 }
491 return json;
492}
493
d0632593
BP
494static struct jsonrpc *
495open_jsonrpc(const char *server)
496{
497 struct stream *stream;
498 int error;
499
f125905c 500 error = stream_open_block(jsonrpc_stream_open(server, &stream,
77f42ca5 501 DSCP_DEFAULT), -1, &stream);
1b0f0f17
BP
502 if (error == EAFNOSUPPORT) {
503 struct pstream *pstream;
504
f125905c 505 error = jsonrpc_pstream_open(server, &pstream, DSCP_DEFAULT);
1b0f0f17
BP
506 if (error) {
507 ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
508 }
509
510 VLOG_INFO("%s: waiting for connection...", server);
511 error = pstream_accept_block(pstream, &stream);
512 if (error) {
513 ovs_fatal(error, "failed to accept connection on \"%s\"", server);
514 }
515
516 pstream_close(pstream);
517 } else if (error) {
d0632593
BP
518 ovs_fatal(error, "failed to connect to \"%s\"", server);
519 }
520
521 return jsonrpc_open(stream);
522}
523
524static void
525print_json(struct json *json)
526{
3a3eb9da 527 char *string = json_to_string(json, table_style.json_flags);
838f9c31 528 puts(string);
d0632593
BP
529 free(string);
530}
531
532static void
533print_and_free_json(struct json *json)
534{
535 print_json(json);
536 json_destroy(json);
537}
538
539static void
540check_ovsdb_error(struct ovsdb_error *error)
541{
542 if (error) {
543 ovs_fatal(0, "%s", ovsdb_error_to_string(error));
544 }
545}
546
547static struct ovsdb_schema *
53ffefe9 548fetch_schema(struct jsonrpc *rpc, const char *database)
d0632593
BP
549{
550 struct jsonrpc_msg *request, *reply;
551 struct ovsdb_schema *schema;
d0632593 552
9cb53f26
BP
553 request = jsonrpc_create_request("get_schema",
554 json_array_create_1(
555 json_string_create(database)),
20bed8be 556 NULL);
d35f8e72 557 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
d0632593
BP
558 check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
559 jsonrpc_msg_destroy(reply);
a8425c53
BP
560
561 return schema;
562}
563
9cb53f26 564static void
9a614624 565fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
9cb53f26
BP
566{
567 struct jsonrpc_msg *request, *reply;
9cb53f26
BP
568 size_t i;
569
9cb53f26
BP
570 request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
571 NULL);
9cb53f26 572
d35f8e72 573 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
9cb53f26
BP
574 if (reply->result->type != JSON_ARRAY) {
575 ovs_fatal(0, "list_dbs response is not array");
576 }
577
fa37affa
BP
578 for (i = 0; i < reply->result->array.n; i++) {
579 const struct json *name = reply->result->array.elems[i];
9cb53f26
BP
580
581 if (name->type != JSON_STRING) {
34582733 582 ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i);
9cb53f26 583 }
fa37affa 584 svec_add(dbs, name->string);
9cb53f26
BP
585 }
586 jsonrpc_msg_destroy(reply);
71fceeb0 587 svec_sort(dbs);
9cb53f26 588}
1b1d2e6d
BP
589
590static const char *
591parse_string_column(const struct json *row, const char *column_name)
592{
593 const struct json *column = shash_find_data(json_object(row), column_name);
594 return column && column->type == JSON_STRING ? json_string(column) : "";
595}
596
597static int
598parse_boolean_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 ? -1
602 : column->type == JSON_TRUE ? true
603 : column->type == JSON_FALSE ? false
604 : -1);
605}
606
607static struct uuid
608parse_uuid_column(const struct json *row, const char *column_name)
609{
610 const struct json *column = shash_find_data(json_object(row), column_name);
611 if (!column) {
612 return UUID_ZERO;
613 }
614
615 struct ovsdb_type type = { OVSDB_BASE_UUID_INIT, OVSDB_BASE_VOID_INIT,
616 0, 1 };
617 struct ovsdb_datum datum;
618 struct ovsdb_error *error = ovsdb_datum_from_json(&datum, &type, column,
619 NULL);
620 if (error) {
621 ovsdb_error_destroy(error);
622 return UUID_ZERO;
623 }
624 struct uuid uuid = datum.n > 0 ? datum.keys[0].uuid : UUID_ZERO;
625 ovsdb_datum_destroy(&datum, &type);
626 return uuid;
627}
628
629struct jsonrpc_msg *
630create_database_info_request(const char *database)
631{
632 struct json *op = json_object_create();
633 json_object_put_string(op, "op", "select");
634 json_object_put_string(op, "table", "Database");
635 struct json *condition = json_array_create_3(
636 json_string_create("name"),
637 json_string_create("=="),
638 json_string_create(database));
639 json_object_put(op, "where", json_array_create_1(condition));
640 struct json *txn = json_array_create_2(
641 json_string_create("_Server"), op);
642 return jsonrpc_create_request("transact", txn, NULL);
643}
644
645static const struct json *
646parse_database_info_reply(const struct jsonrpc_msg *reply, const char *server,
647 const char *database, const struct uuid *cid)
648{
649 const struct json *result = reply->result;
650 if (result->type != JSON_ARRAY
fa37affa
BP
651 || result->array.n != 1
652 || result->array.elems[0]->type != JSON_OBJECT) {
1b1d2e6d
BP
653 VLOG_WARN("%s: unexpected reply to _Server request for %s",
654 server, database);
655 return NULL;
656 }
657
fa37affa 658 const struct json *op_result = result->array.elems[0];
1b1d2e6d
BP
659 const struct json *rows = shash_find_data(json_object(op_result), "rows");
660 if (!rows || rows->type != JSON_ARRAY) {
661 VLOG_WARN("%s: missing \"rows\" member in _Server reply for %s",
662 server, database);
663 return NULL;
664 }
665
fa37affa
BP
666 for (size_t i = 0; i < rows->array.n; i++) {
667 const struct json *row = rows->array.elems[i];
1b1d2e6d
BP
668 if (row->type != JSON_OBJECT) {
669 VLOG_WARN("%s: bad row in _Server reply for %s",
670 server, database);
671 continue;
672 }
673
674 if (strcmp(parse_string_column(row, "name"), database)) {
675 continue;
676 }
677
678 if (cid && !uuid_is_zero(cid)) {
679 struct uuid cid2 = parse_uuid_column(row, "cid");
680 if (!uuid_equals(cid, &cid2)) {
681 continue;
682 }
683 }
684
685 return row;
686 }
687
688 /* No such database. */
689 return NULL;
690}
691
692/* Parses 'reply', a JSON-RPC reply to our request asking for the status of
693 * 'database' on 'server'. Determines whether this server is acceptable for
694 * the transaction we want to make and returns true if so or false to
695 * disconnect and try a different server. */
696static bool
697should_stay_connected(const char *server, const char *database,
698 const struct uuid *cid, const struct jsonrpc_msg *reply)
699{
700 const struct json *row = parse_database_info_reply(reply, server,
701 database, cid);
702 if (!row) {
703 /* No such database. */
704 return false;
705 }
706
707 if (strcmp(parse_string_column(row, "model"), "clustered")) {
708 /* Always accept standalone databases. */
709 return true;
710 }
711
712 if (!parse_boolean_column(row, "connected")) {
713 /* Reject disconnected servers. */
714 return false;
715 }
716
717 if (leader_only && !parse_boolean_column(row, "leader")) {
718 /* Reject if not leader.. */
719 return false;
720 }
721
722 return true;
723}
53ffefe9
BP
724\f
725static void
726do_list_dbs(struct jsonrpc *rpc, const char *database OVS_UNUSED,
727 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
728{
729 const char *db_name;
9a614624
BP
730 struct svec dbs;
731 size_t i;
53ffefe9 732
9a614624 733 svec_init(&dbs);
53ffefe9 734 fetch_dbs(rpc, &dbs);
9a614624 735 SVEC_FOR_EACH (i, db_name, &dbs) {
53ffefe9
BP
736 puts(db_name);
737 }
9a614624 738 svec_destroy(&dbs);
53ffefe9 739}
9cb53f26 740
d0632593 741static void
53ffefe9
BP
742do_get_schema(struct jsonrpc *rpc, const char *database,
743 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593 744{
53ffefe9 745 struct ovsdb_schema *schema = fetch_schema(rpc, database);
d0632593
BP
746 print_and_free_json(ovsdb_schema_to_json(schema));
747 ovsdb_schema_destroy(schema);
748}
749
8159b984 750static void
53ffefe9
BP
751do_get_schema_version(struct jsonrpc *rpc, const char *database,
752 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
8159b984 753{
53ffefe9 754 struct ovsdb_schema *schema = fetch_schema(rpc, database);
8159b984
BP
755 puts(schema->version);
756 ovsdb_schema_destroy(schema);
757}
758
33785c07
BP
759static void
760do_get_schema_cksum(struct jsonrpc *rpc, const char *database,
761 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
762{
763 struct ovsdb_schema *schema = fetch_schema(rpc, database);
764 puts(schema->cksum);
765 ovsdb_schema_destroy(schema);
766}
767
d0632593 768static void
53ffefe9
BP
769do_list_tables(struct jsonrpc *rpc, const char *database,
770 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593
BP
771{
772 struct ovsdb_schema *schema;
773 struct shash_node *node;
774 struct table t;
775
53ffefe9 776 schema = fetch_schema(rpc, database);
d0632593
BP
777 table_init(&t);
778 table_add_column(&t, "Table");
d0632593
BP
779 SHASH_FOR_EACH (node, &schema->tables) {
780 struct ovsdb_table_schema *ts = node->data;
781
782 table_add_row(&t);
772387d5 783 table_add_cell(&t)->text = xstrdup(ts->name);
d0632593
BP
784 }
785 ovsdb_schema_destroy(schema);
3a3eb9da 786 table_print(&t, &table_style);
af65491d 787 table_destroy(&t);
d0632593
BP
788}
789
790static void
53ffefe9
BP
791do_list_columns(struct jsonrpc *rpc, const char *database,
792 int argc OVS_UNUSED, char *argv[])
d0632593 793{
53ffefe9 794 const char *table_name = argv[0];
d0632593
BP
795 struct ovsdb_schema *schema;
796 struct shash_node *table_node;
797 struct table t;
798
53ffefe9 799 schema = fetch_schema(rpc, database);
d0632593
BP
800 table_init(&t);
801 if (!table_name) {
802 table_add_column(&t, "Table");
803 }
804 table_add_column(&t, "Column");
805 table_add_column(&t, "Type");
d0632593
BP
806 SHASH_FOR_EACH (table_node, &schema->tables) {
807 struct ovsdb_table_schema *ts = table_node->data;
808
809 if (!table_name || !strcmp(table_name, ts->name)) {
810 struct shash_node *column_node;
811
812 SHASH_FOR_EACH (column_node, &ts->columns) {
bd76d25d 813 const struct ovsdb_column *column = column_node->data;
d0632593
BP
814
815 table_add_row(&t);
816 if (!table_name) {
772387d5 817 table_add_cell(&t)->text = xstrdup(ts->name);
d0632593 818 }
772387d5
BP
819 table_add_cell(&t)->text = xstrdup(column->name);
820 table_add_cell(&t)->json = ovsdb_type_to_json(&column->type);
d0632593
BP
821 }
822 }
823 }
824 ovsdb_schema_destroy(schema);
3a3eb9da 825 table_print(&t, &table_style);
af65491d 826 table_destroy(&t);
d0632593
BP
827}
828
53178986
BP
829static void
830send_db_change_aware(struct jsonrpc *rpc)
831{
832 if (db_change_aware != 0) {
833 struct jsonrpc_msg *request = jsonrpc_create_request(
834 "set_db_change_aware",
835 json_array_create_1(json_boolean_create(true)),
836 NULL);
837 struct jsonrpc_msg *reply;
838 int error = jsonrpc_transact_block(rpc, request, &reply);
839 if (error) {
840 ovs_fatal(error, "%s: error setting db_change_aware",
841 jsonrpc_get_name(rpc));
842 }
843 if (reply->type == JSONRPC_ERROR && db_change_aware == 1) {
844 ovs_fatal(0, "%s: set_db_change_aware failed (%s)",
845 jsonrpc_get_name(rpc), json_to_string(reply->error, 0));
846 }
847 jsonrpc_msg_destroy(reply);
848 }
849}
850
838f9c31 851static struct json *
1b1d2e6d 852do_transact__(int argc, char *argv[], struct json *transaction)
6d65eee8
BP
853{
854 struct jsonrpc_msg *request, *reply;
1b1d2e6d 855 if (transaction->type != JSON_ARRAY
fa37affa
BP
856 || !transaction->array.n
857 || transaction->array.elems[0]->type != JSON_STRING) {
1b1d2e6d
BP
858 ovs_fatal(0, "not a valid OVSDB query");
859 }
fa37affa 860 const char *db_name = json_string(transaction->array.elems[0]);
1b1d2e6d
BP
861
862 struct jsonrpc *rpc;
863 char *database = CONST_CAST(char *, db_name);
864 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
6d65eee8 865
53178986
BP
866 if (db_change_aware == 1) {
867 send_db_change_aware(rpc);
868 }
869 daemon_save_fd(STDOUT_FILENO);
870 daemon_save_fd(STDERR_FILENO);
871 daemonize();
872
20bed8be 873 request = jsonrpc_create_request("transact", transaction, NULL);
d35f8e72 874 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
838f9c31 875 struct json *result = json_clone(reply->result);
6d65eee8 876 jsonrpc_msg_destroy(reply);
1b1d2e6d 877 jsonrpc_close(rpc);
838f9c31
BP
878
879 return result;
880}
881
882static void
1b1d2e6d
BP
883do_transact(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
884 int argc, char *argv[])
838f9c31 885{
1b1d2e6d 886 print_and_free_json(do_transact__(argc, argv, parse_json(argv[argc - 1])));
838f9c31
BP
887}
888
889static void
1b1d2e6d
BP
890do_query(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
891 int argc, char *argv[])
838f9c31 892{
1b1d2e6d 893 struct json *transaction = parse_json(argv[argc - 1]);
838f9c31
BP
894
895 if (transaction->type != JSON_ARRAY) {
896 ovs_fatal(0, "not a valid OVSDB query");
897 }
898
899 /* Append an "abort" operation to the query. */
900 struct json *abort_op = json_object_create();
901 json_object_put_string(abort_op, "op", "abort");
902 json_array_add(transaction, abort_op);
fa37affa 903 size_t abort_idx = transaction->array.n - 2;
838f9c31
BP
904
905 /* Run query. */
1b1d2e6d 906 struct json *result = do_transact__(argc, argv, transaction);
838f9c31
BP
907
908 /* If the "abort" operation ended the transaction, remove its result. */
909 if (result->type == JSON_ARRAY
fa37affa
BP
910 && result->array.n == abort_idx + 1
911 && result->array.elems[abort_idx]->type == JSON_OBJECT) {
912 struct json *op_result = result->array.elems[abort_idx];
838f9c31
BP
913 struct json *error = shash_find_data(json_object(op_result), "error");
914 if (error
915 && error->type == JSON_STRING
916 && !strcmp(json_string(error), "aborted")) {
fa37affa 917 result->array.n--;
838f9c31
BP
918 json_destroy(op_result);
919 }
920 }
921
922 /* Print the result. */
923 print_and_free_json(result);
6d65eee8 924}
4227b221
BP
925\f
926/* "monitor" command. */
927
928struct monitored_table {
929 struct ovsdb_table_schema *table;
930 struct ovsdb_column_set columns;
931};
6d65eee8 932
a8425c53
BP
933static void
934monitor_print_row(struct json *row, const char *type, const char *uuid,
935 const struct ovsdb_column_set *columns, struct table *t)
936{
937 size_t i;
938
939 if (!row) {
940 ovs_error(0, "missing %s row", type);
941 return;
942 } else if (row->type != JSON_OBJECT) {
943 ovs_error(0, "<row> is not object");
944 return;
945 }
946
947 table_add_row(t);
772387d5
BP
948 table_add_cell(t)->text = xstrdup(uuid);
949 table_add_cell(t)->text = xstrdup(type);
a8425c53
BP
950 for (i = 0; i < columns->n_columns; i++) {
951 const struct ovsdb_column *column = columns->columns[i];
952 struct json *value = shash_find_data(json_object(row), column->name);
772387d5 953 struct cell *cell = table_add_cell(t);
a8425c53 954 if (value) {
772387d5
BP
955 cell->json = json_clone(value);
956 cell->type = &column->type;
a8425c53
BP
957 }
958 }
959}
960
961static void
4227b221
BP
962monitor_print_table(struct json *table_update,
963 const struct monitored_table *mt, char *caption,
964 bool initial)
a8425c53 965{
4227b221
BP
966 const struct ovsdb_table_schema *table = mt->table;
967 const struct ovsdb_column_set *columns = &mt->columns;
a8425c53
BP
968 struct shash_node *node;
969 struct table t;
970 size_t i;
971
a8425c53 972 if (table_update->type != JSON_OBJECT) {
4227b221 973 ovs_error(0, "<table-update> for table %s is not object", table->name);
a8425c53
BP
974 return;
975 }
976
4227b221
BP
977 table_init(&t);
978 table_set_timestamp(&t, timestamp);
979 table_set_caption(&t, caption);
980
a8425c53
BP
981 table_add_column(&t, "row");
982 table_add_column(&t, "action");
983 for (i = 0; i < columns->n_columns; i++) {
984 table_add_column(&t, "%s", columns->columns[i]->name);
985 }
986 SHASH_FOR_EACH (node, json_object(table_update)) {
987 struct json *row_update = node->data;
988 struct json *old, *new;
989
990 if (row_update->type != JSON_OBJECT) {
991 ovs_error(0, "<row-update> is not object");
992 continue;
993 }
994 old = shash_find_data(json_object(row_update), "old");
995 new = shash_find_data(json_object(row_update), "new");
996 if (initial) {
997 monitor_print_row(new, "initial", node->name, columns, &t);
998 } else if (!old) {
999 monitor_print_row(new, "insert", node->name, columns, &t);
1000 } else if (!new) {
1001 monitor_print_row(old, "delete", node->name, columns, &t);
1002 } else {
1003 monitor_print_row(old, "old", node->name, columns, &t);
1004 monitor_print_row(new, "new", "", columns, &t);
1005 }
1006 }
3a3eb9da 1007 table_print(&t, &table_style);
a8425c53
BP
1008 table_destroy(&t);
1009}
1010
4227b221
BP
1011static void
1012monitor_print(struct json *table_updates,
1013 const struct monitored_table *mts, size_t n_mts,
1014 bool initial)
1015{
1016 size_t i;
1017
1018 if (table_updates->type != JSON_OBJECT) {
1019 ovs_error(0, "<table-updates> is not object");
1020 return;
1021 }
1022
1023 for (i = 0; i < n_mts; i++) {
1024 const struct monitored_table *mt = &mts[i];
1025 struct json *table_update = shash_find_data(json_object(table_updates),
1026 mt->table->name);
1027 if (table_update) {
1028 monitor_print_table(table_update, mt,
1029 n_mts > 1 ? xstrdup(mt->table->name) : NULL,
1030 initial);
1031 }
1032 }
1033}
1034
85226894
AZ
1035static void
1036monitor2_print_row(struct json *row, const char *type, const char *uuid,
1037 const struct ovsdb_column_set *columns, struct table *t)
1038{
1039 if (!strcmp(type, "delete")) {
1040 if (row->type != JSON_NULL) {
1041 ovs_error(0, "delete method does not expect <row>");
1042 return;
1043 }
1044
1045 table_add_row(t);
1046 table_add_cell(t)->text = xstrdup(uuid);
1047 table_add_cell(t)->text = xstrdup(type);
1048 } else {
1049 if (!row || row->type != JSON_OBJECT) {
1050 ovs_error(0, "<row> is not object");
1051 return;
1052 }
1053 monitor_print_row(row, type, uuid, columns, t);
1054 }
1055}
1056
1057static void
1058monitor2_print_table(struct json *table_update2,
1059 const struct monitored_table *mt, char *caption)
1060{
1061 const struct ovsdb_table_schema *table = mt->table;
1062 const struct ovsdb_column_set *columns = &mt->columns;
1063 struct shash_node *node;
1064 struct table t;
85226894
AZ
1065
1066 if (table_update2->type != JSON_OBJECT) {
1067 ovs_error(0, "<table-update> for table %s is not object", table->name);
1068 return;
1069 }
1070
1071 table_init(&t);
1072 table_set_timestamp(&t, timestamp);
1073 table_set_caption(&t, caption);
1074
1075 table_add_column(&t, "row");
1076 table_add_column(&t, "action");
17573cf1 1077 for (size_t i = 0; i < columns->n_columns; i++) {
85226894
AZ
1078 table_add_column(&t, "%s", columns->columns[i]->name);
1079 }
1080 SHASH_FOR_EACH (node, json_object(table_update2)) {
1081 struct json *row_update2 = node->data;
1082 const char *operation;
1083 struct json *row;
1084 const char *ops[] = {"delete", "initial", "modify", "insert"};
1085
1086 if (row_update2->type != JSON_OBJECT) {
1087 ovs_error(0, "<row-update2> is not object");
1088 continue;
1089 }
1090
1091 /* row_update2 contains one of objects indexed by ops[] */
1092 for (int i = 0; i < ARRAY_SIZE(ops); i++) {
1093 operation = ops[i];
1094 row = shash_find_data(json_object(row_update2), operation);
1095
1096 if (row) {
1097 monitor2_print_row(row, operation, node->name, columns, &t);
1098 break;
1099 }
1100 }
1101 }
1102 table_print(&t, &table_style);
1103 table_destroy(&t);
1104}
1105
1106static void
1107monitor2_print(struct json *table_updates2,
1108 const struct monitored_table *mts, size_t n_mts)
1109{
1110 size_t i;
1111
1112 if (table_updates2->type != JSON_OBJECT) {
1113 ovs_error(0, "<table-updates2> is not object");
1114 return;
1115 }
1116
1117 for (i = 0; i < n_mts; i++) {
1118 const struct monitored_table *mt = &mts[i];
1119 struct json *table_update = shash_find_data(
1120 json_object(table_updates2),
1121 mt->table->name);
1122 if (table_update) {
1123 monitor2_print_table(table_update, mt,
1124 n_mts > 1 ? xstrdup(mt->table->name) : NULL);
1125 }
1126 }
1127}
1128
a8425c53 1129static void
20aa445d
BP
1130add_column(const char *server, const struct ovsdb_column *column,
1131 struct ovsdb_column_set *columns, struct json *columns_json)
a8425c53 1132{
20aa445d
BP
1133 if (ovsdb_column_set_contains(columns, column->index)) {
1134 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
1135 server, column->name);
a8425c53 1136 }
20aa445d
BP
1137 ovsdb_column_set_add(columns, column);
1138 json_array_add(columns_json, json_string_create(column->name));
1139}
a8425c53 1140
20aa445d
BP
1141static struct json *
1142parse_monitor_columns(char *arg, const char *server, const char *database,
1143 const struct ovsdb_table_schema *table,
1144 struct ovsdb_column_set *columns)
1145{
1146 bool initial, insert, delete, modify;
1147 struct json *mr, *columns_json;
1148 char *save_ptr = NULL;
1149 char *token;
1150
1151 mr = json_object_create();
1152 columns_json = json_array_create_empty();
1153 json_object_put(mr, "columns", columns_json);
1154
1155 initial = insert = delete = modify = true;
1156 for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
1157 token = strtok_r(NULL, ",", &save_ptr)) {
1158 if (!strcmp(token, "!initial")) {
1159 initial = false;
1160 } else if (!strcmp(token, "!insert")) {
1161 insert = false;
1162 } else if (!strcmp(token, "!delete")) {
1163 delete = false;
1164 } else if (!strcmp(token, "!modify")) {
1165 modify = false;
1166 } else {
a8425c53 1167 const struct ovsdb_column *column;
20aa445d 1168
a8425c53
BP
1169 column = ovsdb_table_schema_get_column(table, token);
1170 if (!column) {
9cb53f26
BP
1171 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
1172 "column named \"%s\"",
20aa445d 1173 server, table->name, database, token);
a8425c53 1174 }
20aa445d 1175 add_column(server, column, columns, columns_json);
a8425c53 1176 }
20aa445d
BP
1177 }
1178
fa37affa 1179 if (columns_json->array.n == 0) {
a1ae5dc8
BP
1180 const struct shash_node **nodes;
1181 size_t i, n;
1182
1183 n = shash_count(&table->columns);
1184 nodes = shash_sort(&table->columns);
1185 for (i = 0; i < n; i++) {
1186 const struct ovsdb_column *column = nodes[i]->data;
1187 if (column->index != OVSDB_COL_UUID
1188 && column->index != OVSDB_COL_VERSION) {
20aa445d 1189 add_column(server, column, columns, columns_json);
a8425c53
BP
1190 }
1191 }
a1ae5dc8
BP
1192 free(nodes);
1193
4227b221 1194 add_column(server, ovsdb_table_schema_get_column(table, "_version"),
20aa445d 1195 columns, columns_json);
a8425c53
BP
1196 }
1197
20aa445d
BP
1198 if (!initial || !insert || !delete || !modify) {
1199 struct json *select = json_object_create();
876ba6de
BP
1200 json_object_put(select, "initial", json_boolean_create(initial));
1201 json_object_put(select, "insert", json_boolean_create(insert));
1202 json_object_put(select, "delete", json_boolean_create(delete));
1203 json_object_put(select, "modify", json_boolean_create(modify));
20aa445d
BP
1204 json_object_put(mr, "select", select);
1205 }
1206
1207 return mr;
1208}
1209
1210static void
4227b221
BP
1211ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
1212 const char *argv[] OVS_UNUSED, void *exiting_)
20aa445d 1213{
4227b221
BP
1214 bool *exiting = exiting_;
1215 *exiting = true;
1216 unixctl_command_reply(conn, NULL);
1217}
20aa445d 1218
4227b221
BP
1219static void
1220ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
1221 const char *argv[] OVS_UNUSED, void *blocked_)
1222{
1223 bool *blocked = blocked_;
1224
1225 if (!*blocked) {
1226 *blocked = true;
1227 unixctl_command_reply(conn, NULL);
1228 } else {
1229 unixctl_command_reply(conn, "already blocking");
a8425c53 1230 }
4227b221
BP
1231}
1232
1233static void
1234ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
1235 const char *argv[] OVS_UNUSED, void *blocked_)
1236{
1237 bool *blocked = blocked_;
1238
1239 if (*blocked) {
1240 *blocked = false;
1241 unixctl_command_reply(conn, NULL);
1242 } else {
1243 unixctl_command_reply(conn, "already unblocked");
1244 }
1245}
1246
c383f3bf
LS
1247static void
1248ovsdb_client_cond_change(struct unixctl_conn *conn, int argc OVS_UNUSED,
1249 const char *argv[], void *rpc_)
1250{
1251 struct jsonrpc *rpc = rpc_;
1252 struct json *monitor_cond_update_requests = json_object_create();
1253 struct json *monitor_cond_update_request = json_object_create();
1254 struct json *params;
1255 struct jsonrpc_msg *request;
1256
1257 json_object_put(monitor_cond_update_request, "where",
1258 json_from_string(argv[2]));
1259 json_object_put(monitor_cond_update_requests,
1260 argv[1],
1261 json_array_create_1(monitor_cond_update_request));
1262
1263 params = json_array_create_3(json_null_create(),json_null_create(),
1264 monitor_cond_update_requests);
1265
1266 request = jsonrpc_create_request("monitor_cond_change", params, NULL);
1267 jsonrpc_send(rpc, request);
1268
1269 VLOG_DBG("cond change %s %s", argv[1], argv[2]);
a3f42026 1270 unixctl_command_reply(conn, "condition changed");
c383f3bf
LS
1271}
1272
4227b221
BP
1273static void
1274add_monitored_table(int argc, char *argv[],
1275 const char *server, const char *database,
c383f3bf 1276 struct json *condition,
4227b221
BP
1277 struct ovsdb_table_schema *table,
1278 struct json *monitor_requests,
1279 struct monitored_table **mts,
1280 size_t *n_mts, size_t *allocated_mts)
1281{
c383f3bf 1282 struct json *monitor_request_array, *mr;
4227b221
BP
1283 struct monitored_table *mt;
1284
1285 if (*n_mts >= *allocated_mts) {
1286 *mts = x2nrealloc(*mts, allocated_mts, sizeof **mts);
1287 }
1288 mt = &(*mts)[(*n_mts)++];
1289 mt->table = table;
1290 ovsdb_column_set_init(&mt->columns);
a8425c53 1291
20aa445d 1292 monitor_request_array = json_array_create_empty();
53ffefe9 1293 if (argc > 1) {
20aa445d
BP
1294 int i;
1295
53ffefe9 1296 for (i = 1; i < argc; i++) {
c383f3bf
LS
1297 mr = parse_monitor_columns(argv[i], server, database, table,
1298 &mt->columns);
1299 if (i == 1 && condition) {
1300 json_object_put(mr, "where", condition);
1301 }
1302 json_array_add(monitor_request_array, mr);
20aa445d
BP
1303 }
1304 } else {
4227b221
BP
1305 /* Allocate a writable empty string since parse_monitor_columns()
1306 * is going to strtok() it and that's risky with literal "". */
20aa445d 1307 char empty[] = "";
c383f3bf
LS
1308
1309 mr = parse_monitor_columns(empty, server, database,
1310 table, &mt->columns);
1311 if (condition) {
1312 json_object_put(mr, "where", condition);
1313 }
1314 json_array_add(monitor_request_array, mr);
4227b221
BP
1315 }
1316
1317 json_object_put(monitor_requests, table->name, monitor_request_array);
1318}
1319
12f554b0
WT
1320static void
1321destroy_monitored_table(struct monitored_table *mts, size_t n)
1322{
1323 int i;
1324
1325 for (i = 0; i < n; i++) {
1326 struct monitored_table *mt = &mts[i];
1327 ovsdb_column_set_destroy(&mt->columns);
1328 }
1329
1330 free(mts);
1331}
1332
4227b221 1333static void
85226894
AZ
1334do_monitor__(struct jsonrpc *rpc, const char *database,
1335 enum ovsdb_monitor_version version,
c383f3bf 1336 int argc, char *argv[], struct json *condition)
4227b221
BP
1337{
1338 const char *server = jsonrpc_get_name(rpc);
1339 const char *table_name = argv[0];
1340 struct unixctl_server *unixctl;
1341 struct ovsdb_schema *schema;
4227b221
BP
1342 struct json *monitor, *monitor_requests, *request_id;
1343 bool exiting = false;
1344 bool blocked = false;
1345
1346 struct monitored_table *mts;
1347 size_t n_mts, allocated_mts;
1348
85226894
AZ
1349 ovs_assert(version < OVSDB_MONITOR_VERSION_MAX);
1350
4227b221 1351 daemon_save_fd(STDOUT_FILENO);
53178986 1352 daemon_save_fd(STDERR_FILENO);
e91b927d 1353 daemonize_start(false);
4227b221
BP
1354 if (get_detach()) {
1355 int error;
1356
1357 error = unixctl_server_create(NULL, &unixctl);
1358 if (error) {
1359 ovs_fatal(error, "failed to create unixctl server");
1360 }
1361
1362 unixctl_command_register("exit", "", 0, 0,
1363 ovsdb_client_exit, &exiting);
1364 unixctl_command_register("ovsdb-client/block", "", 0, 0,
1365 ovsdb_client_block, &blocked);
1366 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
1367 ovsdb_client_unblock, &blocked);
c383f3bf
LS
1368 unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
1369 ovsdb_client_cond_change, rpc);
4227b221
BP
1370 } else {
1371 unixctl = NULL;
a8425c53
BP
1372 }
1373
4227b221
BP
1374 schema = fetch_schema(rpc, database);
1375
a8425c53 1376 monitor_requests = json_object_create();
4227b221
BP
1377
1378 mts = NULL;
1379 n_mts = allocated_mts = 0;
1380 if (strcmp(table_name, "ALL")) {
1381 struct ovsdb_table_schema *table;
1382
1383 table = shash_find_data(&schema->tables, table_name);
1384 if (!table) {
1385 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
1386 server, database, table_name);
1387 }
1388
c383f3bf 1389 add_monitored_table(argc, argv, server, database, condition, table,
4227b221
BP
1390 monitor_requests, &mts, &n_mts, &allocated_mts);
1391 } else {
1392 size_t n = shash_count(&schema->tables);
1393 const struct shash_node **nodes = shash_sort(&schema->tables);
1394 size_t i;
1395
c383f3bf
LS
1396 if (condition) {
1397 ovs_fatal(0, "ALL tables are not allowed with condition");
1398 }
1399
4227b221
BP
1400 for (i = 0; i < n; i++) {
1401 struct ovsdb_table_schema *table = nodes[i]->data;
1402
c383f3bf 1403 add_monitored_table(argc, argv, server, database, NULL, table,
4227b221
BP
1404 monitor_requests,
1405 &mts, &n_mts, &allocated_mts);
1406 }
1407 free(nodes);
1408 }
a8425c53 1409
53178986 1410 send_db_change_aware(rpc);
10621d79 1411
9cb53f26
BP
1412 monitor = json_array_create_3(json_string_create(database),
1413 json_null_create(), monitor_requests);
c383f3bf 1414 const char *method = version == OVSDB_MONITOR_V2 ? "monitor_cond"
85226894
AZ
1415 : "monitor";
1416
10621d79 1417 struct jsonrpc_msg *request;
85226894 1418 request = jsonrpc_create_request(method, monitor, NULL);
a8425c53
BP
1419 request_id = json_clone(request->id);
1420 jsonrpc_send(rpc, request);
a8425c53 1421
4227b221
BP
1422 for (;;) {
1423 unixctl_server_run(unixctl);
1424 while (!blocked) {
1425 struct jsonrpc_msg *msg;
1426 int error;
1427
1428 error = jsonrpc_recv(rpc, &msg);
1429 if (error == EAGAIN) {
1430 break;
1431 } else if (error) {
1432 ovs_fatal(error, "%s: receive failed", server);
eb8d3ed6 1433 }
4227b221
BP
1434
1435 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1436 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1437 msg->id));
1438 } else if (msg->type == JSONRPC_REPLY
1439 && json_equal(msg->id, request_id)) {
85226894
AZ
1440 switch(version) {
1441 case OVSDB_MONITOR_V1:
1442 monitor_print(msg->result, mts, n_mts, true);
1443 break;
1444 case OVSDB_MONITOR_V2:
1445 monitor2_print(msg->result, mts, n_mts);
1446 break;
1447 case OVSDB_MONITOR_VERSION_MAX:
1448 default:
1449 OVS_NOT_REACHED();
1450 }
3f262d7d 1451 fflush(stdout);
4227b221
BP
1452 daemonize_complete();
1453 } else if (msg->type == JSONRPC_NOTIFY
1454 && !strcmp(msg->method, "update")) {
1455 struct json *params = msg->params;
1456 if (params->type == JSON_ARRAY
fa37affa
BP
1457 && params->array.n == 2
1458 && params->array.elems[0]->type == JSON_NULL) {
1459 monitor_print(params->array.elems[1], mts, n_mts, false);
4227b221
BP
1460 fflush(stdout);
1461 }
85226894
AZ
1462 } else if (msg->type == JSONRPC_NOTIFY
1463 && version == OVSDB_MONITOR_V2
1464 && !strcmp(msg->method, "update2")) {
1465 struct json *params = msg->params;
1466 if (params->type == JSON_ARRAY
fa37affa
BP
1467 && params->array.n == 2
1468 && params->array.elems[0]->type == JSON_NULL) {
1469 monitor2_print(params->array.elems[1], mts, n_mts);
85226894
AZ
1470 fflush(stdout);
1471 }
53178986
BP
1472 } else if (msg->type == JSONRPC_NOTIFY
1473 && !strcmp(msg->method, "monitor_canceled")) {
1474 ovs_fatal(0, "%s: %s database was removed",
1475 server, database);
a8425c53 1476 }
4227b221
BP
1477 jsonrpc_msg_destroy(msg);
1478 }
1479
1480 if (exiting) {
1481 break;
1482 }
1483
1484 jsonrpc_run(rpc);
1485 jsonrpc_wait(rpc);
1486 if (!blocked) {
1487 jsonrpc_recv_wait(rpc);
a8425c53 1488 }
4227b221
BP
1489 unixctl_server_wait(unixctl);
1490 poll_block();
a8425c53 1491 }
c7edc921
WT
1492
1493 json_destroy(request_id);
1494 unixctl_server_destroy(unixctl);
0ea4fd89 1495 ovsdb_schema_destroy(schema);
12f554b0 1496 destroy_monitored_table(mts, n_mts);
a8425c53
BP
1497}
1498
85226894
AZ
1499static void
1500do_monitor(struct jsonrpc *rpc, const char *database,
1501 int argc, char *argv[])
1502{
c383f3bf 1503 do_monitor__(rpc, database, OVSDB_MONITOR_V1, argc, argv, NULL);
85226894
AZ
1504}
1505
1506static void
c383f3bf 1507do_monitor_cond(struct jsonrpc *rpc, const char *database,
85226894
AZ
1508 int argc, char *argv[])
1509{
c383f3bf
LS
1510 struct ovsdb_condition cnd;
1511 struct json *condition = NULL;
1512 struct ovsdb_schema *schema;
1513 struct ovsdb_table_schema *table;
1514 const char *table_name = argv[1];
1515
1516 ovs_assert(argc > 1);
1517 schema = fetch_schema(rpc, database);
1518 table = shash_find_data(&schema->tables, table_name);
1519 if (!table) {
1520 ovs_fatal(0, "%s does not have a table named \"%s\"",
1521 database, table_name);
1522 }
1523 condition = parse_json(argv[0]);
1524 check_ovsdb_error(ovsdb_condition_from_json(table, condition,
1525 NULL, &cnd));
1526 ovsdb_condition_destroy(&cnd);
1527 do_monitor__(rpc, database, OVSDB_MONITOR_V2, --argc, ++argv, condition);
9b2cc0c3 1528 ovsdb_schema_destroy(schema);
85226894
AZ
1529}
1530
1b1d2e6d
BP
1531static bool
1532is_database_clustered(struct jsonrpc *rpc, const char *database)
1533{
1534 struct jsonrpc_msg *reply;
1535 check_txn(jsonrpc_transact_block(rpc,
1536 create_database_info_request(database),
1537 &reply), &reply);
1538
1539 const struct json *row = parse_database_info_reply(
1540 reply, jsonrpc_get_name(rpc), database, NULL);
1541 return !strcmp(parse_string_column(row, "model"), "clustered");
1542}
1543
53178986 1544static void
1b1d2e6d
BP
1545do_convert(struct jsonrpc *rpc, const char *database_ OVS_UNUSED,
1546 int argc, char *argv[])
53178986 1547{
1b1d2e6d 1548 const char *schema_file_name = argv[argc - 1];
53178986 1549 struct ovsdb_schema *new_schema;
1b1d2e6d
BP
1550 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &new_schema));
1551
1552 char *database = new_schema->name;
1553 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
1554
1555 if (is_database_clustered(rpc, database)) {
1556 ovsdb_schema_persist_ephemeral_columns(new_schema, schema_file_name);
1557 }
1558
1559 send_db_change_aware(rpc);
53178986
BP
1560
1561 struct jsonrpc_msg *request, *reply;
1562 request = jsonrpc_create_request(
1563 "convert",
1564 json_array_create_2(json_string_create(new_schema->name),
1565 ovsdb_schema_to_json(new_schema)), NULL);
1566 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
1567 jsonrpc_msg_destroy(reply);
1568}
1569
1570static void
1b1d2e6d 1571do_needs_conversion(struct jsonrpc *rpc, const char *database_ OVS_UNUSED,
53178986
BP
1572 int argc OVS_UNUSED, char *argv[])
1573{
1574 struct ovsdb_schema *schema1;
1575 check_ovsdb_error(ovsdb_schema_from_file(argv[0], &schema1));
1576
1b1d2e6d
BP
1577 char *database = schema1->name;
1578 open_rpc(1, NEED_DATABASE, argc, argv, &rpc, &database);
1579
1580 if (is_database_clustered(rpc, database)) {
1581 ovsdb_schema_persist_ephemeral_columns(schema1, argv[0]);
1582 }
1583
53178986
BP
1584 struct ovsdb_schema *schema2 = fetch_schema(rpc, schema1->name);
1585 puts(ovsdb_schema_equal(schema1, schema2) ? "no" : "yes");
1586 ovsdb_schema_destroy(schema1);
1587 ovsdb_schema_destroy(schema2);
1588}
1589
25c269ef
BP
1590struct dump_table_aux {
1591 struct ovsdb_datum **data;
1592 const struct ovsdb_column **columns;
1593 size_t n_columns;
1594};
1595
1596static int
1597compare_data(size_t a_y, size_t b_y, size_t x,
1598 const struct dump_table_aux *aux)
1599{
1600 return ovsdb_datum_compare_3way(&aux->data[a_y][x],
1601 &aux->data[b_y][x],
1602 &aux->columns[x]->type);
1603}
1604
1605static int
1606compare_rows(size_t a_y, size_t b_y, void *aux_)
1607{
1608 struct dump_table_aux *aux = aux_;
1609 size_t x;
1610
1611 /* Skip UUID columns on the first pass, since their values tend to be
1612 * random and make our results less reproducible. */
1613 for (x = 0; x < aux->n_columns; x++) {
1614 if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
1615 int cmp = compare_data(a_y, b_y, x, aux);
1616 if (cmp) {
1617 return cmp;
1618 }
1619 }
1620 }
1621
1622 /* Use UUID columns as tie-breakers. */
1623 for (x = 0; x < aux->n_columns; x++) {
1624 if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
1625 int cmp = compare_data(a_y, b_y, x, aux);
1626 if (cmp) {
1627 return cmp;
1628 }
1629 }
1630 }
1631
1632 return 0;
1633}
1634
1635static void
1636swap_rows(size_t a_y, size_t b_y, void *aux_)
1637{
1638 struct dump_table_aux *aux = aux_;
1639 struct ovsdb_datum *tmp = aux->data[a_y];
1640 aux->data[a_y] = aux->data[b_y];
1641 aux->data[b_y] = tmp;
1642}
1643
25c269ef
BP
1644static int
1645compare_columns(const void *a_, const void *b_)
1646{
1647 const struct ovsdb_column *const *ap = a_;
1648 const struct ovsdb_column *const *bp = b_;
1649 const struct ovsdb_column *a = *ap;
1650 const struct ovsdb_column *b = *bp;
1651
1652 return strcmp(a->name, b->name);
1653}
1654
1655static void
b30aa413
BV
1656dump_table(const char *table_name, const struct shash *cols,
1657 struct json_array *rows)
25c269ef
BP
1658{
1659 const struct ovsdb_column **columns;
1660 size_t n_columns;
1661
1662 struct ovsdb_datum **data;
1663
1664 struct dump_table_aux aux;
1665 struct shash_node *node;
1666 struct table t;
1667 size_t x, y;
1668
1669 /* Sort columns by name, for reproducibility. */
b30aa413 1670 columns = xmalloc(shash_count(cols) * sizeof *columns);
25c269ef 1671 n_columns = 0;
b30aa413 1672 SHASH_FOR_EACH (node, cols) {
25c269ef
BP
1673 struct ovsdb_column *column = node->data;
1674 if (strcmp(column->name, "_version")) {
1675 columns[n_columns++] = column;
1676 }
1677 }
1678 qsort(columns, n_columns, sizeof *columns, compare_columns);
1679
1680 /* Extract data from table. */
1681 data = xmalloc(rows->n * sizeof *data);
1682 for (y = 0; y < rows->n; y++) {
1683 struct shash *row;
1684
1685 if (rows->elems[y]->type != JSON_OBJECT) {
34582733 1686 ovs_fatal(0, "row %"PRIuSIZE" in table %s response is not a JSON object: "
b30aa413 1687 "%s", y, table_name, json_to_string(rows->elems[y], 0));
25c269ef
BP
1688 }
1689 row = json_object(rows->elems[y]);
1690
1691 data[y] = xmalloc(n_columns * sizeof **data);
1692 for (x = 0; x < n_columns; x++) {
1693 const struct json *json = shash_find_data(row, columns[x]->name);
1694 if (!json) {
34582733 1695 ovs_fatal(0, "row %"PRIuSIZE" in table %s response lacks %s column",
b30aa413 1696 y, table_name, columns[x]->name);
25c269ef
BP
1697 }
1698
9041097a
BP
1699 check_ovsdb_error(ovsdb_unconstrained_datum_from_json(
1700 &data[y][x], &columns[x]->type, json));
25c269ef
BP
1701 }
1702 }
1703
1704 /* Sort rows by column values, for reproducibility. */
1705 aux.data = data;
1706 aux.columns = columns;
1707 aux.n_columns = n_columns;
1708 sort(rows->n, compare_rows, swap_rows, &aux);
1709
1710 /* Add column headings. */
1711 table_init(&t);
b30aa413 1712 table_set_caption(&t, xasprintf("%s table", table_name));
25c269ef
BP
1713 for (x = 0; x < n_columns; x++) {
1714 table_add_column(&t, "%s", columns[x]->name);
1715 }
1716
1717 /* Print rows. */
1718 for (y = 0; y < rows->n; y++) {
1719 table_add_row(&t);
1720 for (x = 0; x < n_columns; x++) {
772387d5
BP
1721 struct cell *cell = table_add_cell(&t);
1722 cell->json = ovsdb_datum_to_json(&data[y][x], &columns[x]->type);
1723 cell->type = &columns[x]->type;
e49190c4 1724 ovsdb_datum_destroy(&data[y][x], &columns[x]->type);
25c269ef 1725 }
e49190c4 1726 free(data[y]);
25c269ef 1727 }
3a3eb9da 1728 table_print(&t, &table_style);
25c269ef 1729 table_destroy(&t);
e49190c4
BP
1730
1731 free(data);
1732 free(columns);
25c269ef
BP
1733}
1734
1735static void
53ffefe9 1736do_dump(struct jsonrpc *rpc, const char *database,
b30aa413 1737 int argc, char *argv[])
25c269ef 1738{
25c269ef
BP
1739 struct jsonrpc_msg *request, *reply;
1740 struct ovsdb_schema *schema;
1741 struct json *transaction;
25c269ef 1742
b30aa413 1743 const struct shash_node *node, **tables;
25c269ef 1744 size_t n_tables;
b30aa413
BV
1745 struct ovsdb_table_schema *tschema;
1746 const struct shash *columns;
1747 struct shash custom_columns;
25c269ef
BP
1748
1749 size_t i;
1750
b30aa413 1751 shash_init(&custom_columns);
53ffefe9 1752 schema = fetch_schema(rpc, database);
b30aa413
BV
1753 if (argc) {
1754 node = shash_find(&schema->tables, argv[0]);
1755 if (!node) {
1756 ovs_fatal(0, "No table \"%s\" found.", argv[0]);
1757 }
2b03ef95 1758 tables = xmemdup(&node, sizeof node);
b30aa413
BV
1759 n_tables = 1;
1760 tschema = tables[0]->data;
1761 for (i = 1; i < argc; i++) {
1762 node = shash_find(&tschema->columns, argv[i]);
1763 if (!node) {
0d5450a2 1764 ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[i]);
b30aa413 1765 }
0d5450a2 1766 shash_add(&custom_columns, argv[i], node->data);
b30aa413
BV
1767 }
1768 } else {
1769 tables = shash_sort(&schema->tables);
1770 n_tables = shash_count(&schema->tables);
1771 }
25c269ef
BP
1772
1773 /* Construct transaction to retrieve entire database. */
1774 transaction = json_array_create_1(json_string_create(database));
1775 for (i = 0; i < n_tables; i++) {
1776 const struct ovsdb_table_schema *ts = tables[i]->data;
b30aa413 1777 struct json *op, *jcolumns;
25c269ef 1778
b30aa413
BV
1779 if (argc > 1) {
1780 columns = &custom_columns;
1781 } else {
1782 columns = &ts->columns;
1783 }
1784 jcolumns = json_array_create_empty();
1785 SHASH_FOR_EACH (node, columns) {
25c269ef
BP
1786 const struct ovsdb_column *column = node->data;
1787
1788 if (strcmp(column->name, "_version")) {
b30aa413 1789 json_array_add(jcolumns, json_string_create(column->name));
25c269ef
BP
1790 }
1791 }
1792
1793 op = json_object_create();
1794 json_object_put_string(op, "op", "select");
1795 json_object_put_string(op, "table", tables[i]->name);
1796 json_object_put(op, "where", json_array_create_empty());
b30aa413 1797 json_object_put(op, "columns", jcolumns);
25c269ef
BP
1798 json_array_add(transaction, op);
1799 }
1800
1801 /* Send request, get reply. */
1802 request = jsonrpc_create_request("transact", transaction, NULL);
d35f8e72 1803 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
25c269ef
BP
1804
1805 /* Print database contents. */
1806 if (reply->result->type != JSON_ARRAY
fa37affa 1807 || reply->result->array.n != n_tables) {
34582733 1808 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
25c269ef
BP
1809 n_tables, json_to_string(reply->result, 0));
1810 }
1811 for (i = 0; i < n_tables; i++) {
1812 const struct ovsdb_table_schema *ts = tables[i]->data;
fa37affa 1813 const struct json *op_result = reply->result->array.elems[i];
25c269ef
BP
1814 struct json *rows;
1815
1816 if (op_result->type != JSON_OBJECT
1817 || !(rows = shash_find_data(json_object(op_result), "rows"))
1818 || rows->type != JSON_ARRAY) {
1819 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1820 "member array: %s",
1821 ts->name, json_to_string(op_result, 0));
1822 }
1823
b30aa413 1824 if (argc > 1) {
fa37affa 1825 dump_table(tables[i]->name, &custom_columns, &rows->array);
b30aa413 1826 } else {
fa37affa 1827 dump_table(tables[i]->name, &ts->columns, &rows->array);
b30aa413 1828 }
25c269ef 1829 }
e49190c4
BP
1830
1831 jsonrpc_msg_destroy(reply);
b30aa413 1832 shash_destroy(&custom_columns);
e49190c4
BP
1833 free(tables);
1834 ovsdb_schema_destroy(schema);
25c269ef
BP
1835}
1836
4d0a31b6
BP
1837static void
1838print_and_free_log_record(struct json *record)
1839{
1840 struct ds header = DS_EMPTY_INITIALIZER;
1841 struct ds data = DS_EMPTY_INITIALIZER;
19b276cb 1842 ovsdb_log_compose_record(record, OVSDB_MAGIC, &header, &data);
4d0a31b6
BP
1843 fwrite(header.string, header.length, 1, stdout);
1844 fwrite(data.string, data.length, 1, stdout);
1845 ds_destroy(&data);
1846 ds_destroy(&header);
1847 json_destroy(record);
1848}
1849
cb8cbbbe
AGS
1850static void
1851set_binary_mode(FILE *stream OVS_UNUSED)
1852{
1853#ifdef _WIN32
1854 fflush(stream);
1855 /* On Windows set binary mode on the file descriptor to avoid
1856 * translation (i.e. CRLF line endings). */
1857 if (_setmode(_fileno(stream), O_BINARY) == -1) {
1858 ovs_fatal(errno, "could not set binary mode on fd %d",
1859 _fileno(stream));
1860 }
1861#endif
1862}
1863
4d0a31b6
BP
1864static void
1865do_backup(struct jsonrpc *rpc, const char *database,
1866 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1867{
1868 if (isatty(STDOUT_FILENO)) {
1869 ovs_fatal(0, "not writing backup to a terminal; "
1870 "please redirect stdout to a file");
1871 }
cb8cbbbe 1872 set_binary_mode(stdout);
4d0a31b6
BP
1873
1874 /* Get schema. */
1875 struct ovsdb_schema *schema = fetch_schema(rpc, database);
1876
1877 /* Construct transaction to retrieve all tables. */
1878 struct json *txn = json_array_create_1(json_string_create(database));
1879 struct shash_node *node;
1880 SHASH_FOR_EACH (node, &schema->tables) {
1881 const char *table_name = node->name;
1882 const struct ovsdb_table_schema *table = node->data;
1883
1884 /* Get all the columns except _version and the ephemeral ones.
1885 *
1886 * We don't omit tables that only have ephemeral columns because of the
1887 * possibility that other tables references rows in those tables; that
1888 * is, even if all the columns are ephemeral, the rows themselves are
1889 * not. */
1890 struct json *columns = json_array_create_empty();
1891 struct shash_node *node2;
1892 SHASH_FOR_EACH (node2, &table->columns) {
1893 const struct ovsdb_column *column = node2->data;
1894
1895 if (column->persistent) {
1896 if (!columns) {
1897 columns = json_array_create_empty();
1898 }
1899 json_array_add(columns, json_string_create(column->name));
1900 }
1901 }
1902
1903 struct json *op = json_object_create();
1904 json_object_put_string(op, "op", "select");
1905 json_object_put_string(op, "table", table_name);
1906 json_object_put(op, "where", json_array_create_empty());
1907 json_object_put(op, "columns", columns);
1908 json_array_add(txn, op);
1909 }
1910
1911 /* Send request, get reply. */
1912 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
1913 struct jsonrpc_msg *reply;
1914 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
1915
1916 /* Print schema record. */
1917 print_and_free_log_record(ovsdb_schema_to_json(schema));
1918
1919 /* Print database transaction record. */
1920 if (reply->result->type != JSON_ARRAY
fa37affa 1921 || reply->result->array.n != shash_count(&schema->tables)) {
4d0a31b6
BP
1922 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
1923 shash_count(&schema->tables),
1924 json_to_string(reply->result, 0));
1925 }
1926 struct json *output_txn = json_object_create();
1927
1928 size_t i = 0;
1929 SHASH_FOR_EACH (node, &schema->tables) {
1930 const char *table_name = node->name;
1931 const struct ovsdb_table_schema *table = node->data;
fa37affa 1932 const struct json *op_result = reply->result->array.elems[i++];
4d0a31b6
BP
1933 struct json *rows;
1934
1935 if (op_result->type != JSON_OBJECT
1936 || !(rows = shash_find_data(json_object(op_result), "rows"))
1937 || rows->type != JSON_ARRAY) {
1938 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1939 "member array: %s",
1940 table->name, json_to_string(op_result, 0));
1941 }
1942
fa37affa 1943 if (!rows->array.n) {
4d0a31b6
BP
1944 continue;
1945 }
1946
1947 struct json *output_rows = json_object_create();
fa37affa
BP
1948 for (size_t j = 0; j < rows->array.n; j++) {
1949 struct json *row = rows->array.elems[j];
4d0a31b6
BP
1950 if (row->type != JSON_OBJECT) {
1951 ovs_fatal(0, "%s table reply row is not an object: %s",
1952 table_name, json_to_string(row, 0));
1953 }
1954
1955 struct json *uuid_json = shash_find_and_delete(json_object(row),
1956 "_uuid");
1957 if (!uuid_json) {
1958 ovs_fatal(0, "%s table reply row lacks _uuid member: %s",
1959 table_name, json_to_string(row, 0));
1960 }
1961
1962 const struct ovsdb_base_type uuid_base = OVSDB_BASE_UUID_INIT;
1963 union ovsdb_atom atom;
1964 check_ovsdb_error(ovsdb_atom_from_json(&atom, &uuid_base,
1965 uuid_json, NULL));
1966
1967 char uuid_s[UUID_LEN + 1];
1968 snprintf(uuid_s, sizeof uuid_s, UUID_FMT, UUID_ARGS(&atom.uuid));
1969 json_object_put(output_rows, uuid_s, json_clone(row));
1970 }
1971 json_object_put(output_txn, table_name, output_rows);
1972 }
1973 output_txn = ovsdb_file_txn_annotate(
1974 output_txn, "produced by \"ovsdb-client backup\"");
1975 print_and_free_log_record(output_txn);
1976
1977 ovsdb_schema_destroy(schema);
1978 jsonrpc_msg_destroy(reply);
1979}
1980
1b1d2e6d
BP
1981static void
1982check_transaction_reply(struct jsonrpc_msg *reply)
1983{
1984 if (reply->result->type != JSON_ARRAY) {
1985 ovs_fatal(0, "result is not array");
1986 }
1987 for (size_t i = 0; i < json_array(reply->result)->n; i++) {
1988 struct json *json = json_array(reply->result)->elems[i];
1989 if (json->type != JSON_OBJECT) {
1990 ovs_fatal(0, "result array element is not object");
1991 }
1992 struct shash *object = json_object(json);
1993 if (shash_find(object, "error")) {
1994 ovs_fatal(0, "server returned error reply: %s",
1995 json_to_string(json, JSSF_SORT));
1996 }
1997 }
1998}
1999
fe0fb885
BP
2000static void
2001do_restore(struct jsonrpc *rpc, const char *database,
2002 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
2003{
2004 if (isatty(STDIN_FILENO)) {
2005 ovs_fatal(0, "not reading backup from a terminal; "
2006 "please redirect stdin from a file");
2007 }
cb8cbbbe 2008 set_binary_mode(stdin);
fe0fb885 2009
1b1d2e6d
BP
2010 struct ovsdb *backup = ovsdb_file_read("/dev/stdin", false);
2011 ovsdb_storage_close(backup->storage);
2012 backup->storage = NULL;
fe0fb885 2013
1b1d2e6d
BP
2014 struct ovsdb_schema *online_schema = fetch_schema(rpc, database);
2015 if (!ovsdb_schema_equal(backup->schema, online_schema)) {
fe0fb885 2016 struct ds s = DS_EMPTY_INITIALIZER;
1b1d2e6d 2017 if (strcmp(backup->schema->version, online_schema->version)) {
fe0fb885
BP
2018 ds_put_format(&s, "backup schema has version \"%s\" but "
2019 "database schema has version \"%s\"",
1b1d2e6d 2020 backup->schema->version, online_schema->version);
fe0fb885
BP
2021 } else {
2022 ds_put_format(&s, "backup schema and database schema are "
2023 "both version %s but still differ",
1b1d2e6d 2024 backup->schema->version);
fe0fb885
BP
2025 }
2026 if (!force) {
2027 ovs_fatal(0, "%s (use --force to override differences, or "
2028 "\"ovsdb-client convert\" to change the schema)",
2029 ds_cstr(&s));
2030 }
2031 VLOG_INFO("%s", ds_cstr(&s));
2032 ds_destroy(&s);
2033 }
1b1d2e6d 2034 ovsdb_schema_destroy(online_schema);
fe0fb885
BP
2035
2036 struct json *txn = json_array_create_empty();
1b1d2e6d 2037 json_array_add(txn, json_string_create(backup->schema->name));
fe0fb885
BP
2038 struct shash_node *node;
2039 SHASH_FOR_EACH (node, &backup->tables) {
2040 const char *table_name = node->name;
2041 struct ovsdb_table *table = node->data;
2042
2043 struct json *del_op = json_object_create();
2044 json_object_put_string(del_op, "op", "delete");
2045 json_object_put_string(del_op, "table", table_name);
2046 json_object_put(del_op, "where", json_array_create_empty());
2047 json_array_add(txn, del_op);
2048
2049 const struct ovsdb_row *row;
2050 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
2051 struct json *ins_op = json_object_create();
2052 json_object_put_string(ins_op, "op", "insert");
2053 json_object_put_string(ins_op, "table", table_name);
2054 json_object_put(ins_op, "uuid-name",
2055 json_string_create_nocopy(
2056 ovsdb_data_row_name(ovsdb_row_get_uuid(row))));
2057 struct json *row_json = json_object_create();
2058 json_object_put(ins_op, "row", row_json);
2059
2060 struct shash_node *node2;
2061 SHASH_FOR_EACH (node2, &table->schema->columns) {
2062 const struct ovsdb_column *column = node2->data;
2063 const struct ovsdb_datum *datum = &row->fields[column->index];
2064 const struct ovsdb_type *type = &column->type;
2065 if (column->persistent
2066 && column->index >= OVSDB_N_STD_COLUMNS
2067 && !ovsdb_datum_is_default(datum, type)) {
2068 struct json *value = ovsdb_datum_to_json_with_row_names(
2069 datum, type);
2070 json_object_put(row_json, column->name, value);
2071 }
2072 }
2073 json_array_add(txn, ins_op);
2074 }
2075 }
a34eba01 2076 ovsdb_destroy(backup);
fe0fb885
BP
2077 struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
2078 struct jsonrpc_msg *reply;
2079 check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
1b1d2e6d 2080 check_transaction_reply(reply);
fe0fb885
BP
2081 jsonrpc_msg_destroy(reply);
2082}
2083
2084
d0632593 2085static void
53ffefe9
BP
2086do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
2087 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593
BP
2088{
2089 usage();
2090}
2091
9aeba3f4
AZ
2092\f
2093/* "lock" command. */
2094
2095struct ovsdb_client_lock_req {
2096 const char *method;
2097 char *lock;
2098};
2099
2100static void
2101lock_req_init(struct ovsdb_client_lock_req *lock_req,
2102 const char *method, const char *lock_name)
2103{
2104 if (lock_req->method || lock_req->lock) {
2105 return;
2106 }
2107 lock_req->method = method;
2108 lock_req->lock = xstrdup(lock_name);
2109}
2110
2111static bool
2112lock_req_is_set(struct ovsdb_client_lock_req *lock_req)
2113{
2114 return lock_req->method;
2115}
2116
2117static void
2118lock_req_destroy(struct ovsdb_client_lock_req *lock_req)
2119{
2120 free(lock_req->lock);
2121 lock_req->method = NULL;
2122 lock_req->lock = NULL;
2123}
2124
2125/* Create a lock class request. Caller is responsible for free
2126 * the 'request' message. */
2127static struct jsonrpc_msg *
2128create_lock_request(struct ovsdb_client_lock_req *lock_req)
2129{
2130 struct json *locks, *lock;
2131
2132 locks = json_array_create_empty();
2133 lock = json_string_create(lock_req->lock);
2134 json_array_add(locks, lock);
2135
2136 return jsonrpc_create_request(lock_req->method, locks, NULL);
2137}
2138
2139static void
2140ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED,
2141 const char *argv[], void *lock_req_)
2142{
2143 struct ovsdb_client_lock_req *lock_req = lock_req_;
2144 lock_req_init(lock_req, "lock", argv[1]);
2145 unixctl_command_reply(conn, NULL);
2146}
2147
2148static void
2149ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED,
2150 const char *argv[], void *lock_req_)
2151{
2152 struct ovsdb_client_lock_req *lock_req = lock_req_;
2153 lock_req_init(lock_req, "unlock", argv[1]);
2154 unixctl_command_reply(conn, NULL);
2155}
2156
2157static void
2158ovsdb_client_steal(struct unixctl_conn *conn, int argc OVS_UNUSED,
2159 const char *argv[], void *lock_req_)
2160{
2161 struct ovsdb_client_lock_req *lock_req = lock_req_;
2162 lock_req_init(lock_req, "steal", argv[1]);
2163 unixctl_command_reply(conn, NULL);
2164}
2165
2166static void
2167do_lock(struct jsonrpc *rpc, const char *method, const char *lock)
2168{
2169 struct ovsdb_client_lock_req lock_req = {NULL, NULL};
2170 struct unixctl_server *unixctl;
2171 struct jsonrpc_msg *request;
2172 struct json *request_id = NULL;
2173 bool exiting = false;
2174 bool enable_lock_request = true; /* Don't send another request before
2175 getting a reply of the previous
2176 request. */
2177 daemon_save_fd(STDOUT_FILENO);
2178 daemonize_start(false);
2179 lock_req_init(&lock_req, method, lock);
2180
2181 if (get_detach()) {
2182 int error;
2183
2184 error = unixctl_server_create(NULL, &unixctl);
2185 if (error) {
2186 ovs_fatal(error, "failed to create unixctl server");
2187 }
2188
2189 unixctl_command_register("unlock", "LOCK", 1, 1,
2190 ovsdb_client_unlock, &lock_req);
2191 unixctl_command_register("steal", "LOCK", 1, 1,
2192 ovsdb_client_steal, &lock_req);
2193 unixctl_command_register("lock", "LOCK", 1, 1,
2194 ovsdb_client_lock, &lock_req);
2195 unixctl_command_register("exit", "", 0, 0,
2196 ovsdb_client_exit, &exiting);
2197 } else {
2198 unixctl = NULL;
2199 }
2200
2201 for (;;) {
2202 struct jsonrpc_msg *msg;
2203 int error;
2204
2205 unixctl_server_run(unixctl);
2206 if (enable_lock_request && lock_req_is_set(&lock_req)) {
2207 request = create_lock_request(&lock_req);
2208 request_id = json_clone(request->id);
2209 jsonrpc_send(rpc, request);
2210 lock_req_destroy(&lock_req);
2211 }
2212
2213 error = jsonrpc_recv(rpc, &msg);
2214 if (error == EAGAIN) {
2215 goto no_msg;
2216 } else if (error) {
2217 ovs_fatal(error, "%s: receive failed", jsonrpc_get_name(rpc));
2218 }
2219
2220 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
2221 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
2222 msg->id));
2223 } else if (msg->type == JSONRPC_REPLY
2224 && json_equal(msg->id, request_id)) {
2225 print_json(msg->result);
9aeba3f4
AZ
2226 fflush(stdout);
2227 enable_lock_request = true;
2228 json_destroy(request_id);
2229 request_id = NULL;
2230 daemonize_complete();
2231 } else if (msg->type == JSONRPC_NOTIFY) {
2232 puts(msg->method);
2233 print_json(msg->params);
9aeba3f4
AZ
2234 fflush(stdout);
2235 }
2236
2237 jsonrpc_msg_destroy(msg);
2238
2239no_msg:
2240 if (exiting) {
2241 break;
2242 }
2243
2244 jsonrpc_run(rpc);
2245 jsonrpc_wait(rpc);
2246 jsonrpc_recv_wait(rpc);
2247
2248 unixctl_server_wait(unixctl);
2249 poll_block();
2250 }
2251
2252 json_destroy(request_id);
2253 unixctl_server_destroy(unixctl);
2254}
2255
2256static void
2257do_lock_create(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2258 int argc OVS_UNUSED, char *argv[])
2259{
2260 do_lock(rpc, "lock", argv[0]);
2261}
2262
2263static void
2264do_lock_steal(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2265 int argc OVS_UNUSED, char *argv[])
2266{
2267 do_lock(rpc, "steal", argv[0]);
2268}
2269
2270static void
2271do_lock_unlock(struct jsonrpc *rpc, const char *database OVS_UNUSED,
2272 int argc OVS_UNUSED, char *argv[])
2273{
2274 do_lock(rpc, "unlock", argv[0]);
2275}
2276
1b1d2e6d
BP
2277enum ovsdb_client_wait_type {
2278 WAIT_CONNECTED,
2279 WAIT_ADDED,
2280 WAIT_REMOVED
2281};
2282
2283static struct jsonrpc_msg *
2284compose_wait_transaction(enum ovsdb_client_wait_type type,
2285 const char *database)
2286{
2287 struct json *txn = json_array_create_empty();
2288 json_array_add(txn, json_string_create("_Server"));
2289
2290 struct json *op = json_object_create();
2291 json_array_add(txn, op);
2292 json_object_put_string(op, "op", "wait");
2293 json_object_put_string(op, "table", "Database");
2294 json_object_put(op, "where",
2295 json_array_create_1(
2296 json_array_create_3(
2297 json_string_create("name"),
2298 json_string_create("=="),
2299 json_string_create(database))));
2300
2301 if (type == WAIT_CONNECTED) {
2302 /* Wait until connected == true. */
2303 json_object_put(op, "columns",
2304 json_array_create_1(json_string_create("connected")));
2305 json_object_put_string(op, "until", "==");
2306
2307 struct json *row = json_object_create();
2308 json_object_put(row, "connected", json_boolean_create(true));
2309 json_object_put(op, "rows", json_array_create_1(row));
2310 } else {
2311 ovs_assert(type == WAIT_ADDED || type == WAIT_REMOVED);
2312
2313 /* Wait until such a row exists, or not, respectively. */
2314 json_object_put(op, "columns", json_array_create_empty());
2315 json_object_put_string(op, "until", "==");
2316 json_object_put(op, "rows",
2317 (type == WAIT_ADDED
2318 ? json_array_create_1(json_object_create())
2319 : json_array_create_empty()));
2320 }
2321 return jsonrpc_create_request("transact", txn, NULL);
2322}
2323
2324static void
2325do_wait(struct jsonrpc *rpc_unused OVS_UNUSED,
2326 const char *database_unused OVS_UNUSED,
2327 int argc, char *argv[])
2328{
1b1d2e6d
BP
2329 const char *database = argv[argc - 2];
2330 const char *state = argv[argc - 1];
2331
2332 enum ovsdb_client_wait_type type;
2333 if (!strcmp(state, "connected")) {
2334 type = WAIT_CONNECTED;
2335 } else if (!strcmp(state, "added")) {
2336 type = WAIT_ADDED;
2337 } else if (!strcmp(state, "removed")) {
2338 type = WAIT_REMOVED;
2339 } else {
2340 ovs_fatal(0, "%s: unknown state", state);
2341 }
2342
2343 char *remote = argc > 2 ? xstrdup(argv[0]) : default_remote();
2344 struct jsonrpc_session *js = jsonrpc_session_open(remote, true);
2345 free(remote);
2346
2347 unsigned int seqno = 0;
2348 struct json *sdca_id = NULL;
2349 struct json *txn_id = NULL;
2350 for (;;) {
2351 jsonrpc_session_run(js);
2352
2353 if (seqno != jsonrpc_session_get_seqno(js)
2354 && jsonrpc_session_is_connected(js)) {
2355 seqno = jsonrpc_session_get_seqno(js);
2356
2357 /* Send set_db_change_aware request. */
2358 struct jsonrpc_msg *rq = jsonrpc_create_request(
2359 "set_db_change_aware",
2360 json_array_create_1(json_boolean_create(true)),
2361 NULL);
2362 json_destroy(sdca_id);
2363 sdca_id = json_clone(rq->id);
2364 jsonrpc_session_send(js, rq);
2365
2366 /* Send transaction. */
2367 rq = compose_wait_transaction(type, database);
2368 json_destroy(txn_id);
2369 txn_id = json_clone(rq->id);
2370 jsonrpc_session_send(js, rq);
2371 }
2372
2373 struct jsonrpc_msg *reply = jsonrpc_session_recv(js);
2374 if (reply && reply->id) {
2375 if (sdca_id && json_equal(sdca_id, reply->id)) {
2376 if (reply->type == JSONRPC_ERROR) {
2377 ovs_fatal(0, "%s: set_db_change_aware failed (%s)",
2378 jsonrpc_session_get_name(js),
2379 json_to_string(reply->error, 0));
2380 }
2381 } else if (txn_id && json_equal(txn_id, reply->id)) {
2382 check_transaction_reply(reply);
2383 exit(0);
2384 }
2385 }
2386 jsonrpc_msg_destroy(reply);
2387
2388 jsonrpc_session_recv_wait(js);
2389 jsonrpc_session_wait(js);
2390 poll_block();
2391 }
2392}
2393
2394/* Command handlers may take an optional server socket name (e.g. "unix:...")
2395 * and an optional database name (e.g. Open_vSwitch) as their initial
2396 * arguments. The NEED_* element indicates what a particular command needs.
2397 * These optional arguments should not be included in min_args or max_args, and
2398 * they are not included in the argc and argv arguments passed to the handler:
2399 * the argv[0] passed to the handler is the first argument after the optional
2400 * server socket name. */
53ffefe9
BP
2401static const struct ovsdb_client_command all_commands[] = {
2402 { "list-dbs", NEED_RPC, 0, 0, do_list_dbs },
2403 { "get-schema", NEED_DATABASE, 0, 0, do_get_schema },
2404 { "get-schema-version", NEED_DATABASE, 0, 0, do_get_schema_version },
33785c07 2405 { "get-schema-cksum", NEED_DATABASE, 0, 0, do_get_schema_cksum },
53ffefe9
BP
2406 { "list-tables", NEED_DATABASE, 0, 0, do_list_tables },
2407 { "list-columns", NEED_DATABASE, 0, 1, do_list_columns },
1b1d2e6d
BP
2408 { "transact", NEED_NONE, 1, 2, do_transact },
2409 { "query", NEED_NONE, 1, 2, do_query },
53ffefe9 2410 { "monitor", NEED_DATABASE, 1, INT_MAX, do_monitor },
c383f3bf 2411 { "monitor-cond", NEED_DATABASE, 2, 3, do_monitor_cond },
1b1d2e6d
BP
2412 { "wait", NEED_NONE, 2, 3, do_wait },
2413 { "convert", NEED_NONE, 1, 2, do_convert },
2414 { "needs-conversion", NEED_NONE, 1, 2, do_needs_conversion },
b30aa413 2415 { "dump", NEED_DATABASE, 0, INT_MAX, do_dump },
4d0a31b6 2416 { "backup", NEED_DATABASE, 0, 0, do_backup },
fe0fb885 2417 { "restore", NEED_DATABASE, 0, 0, do_restore },
9aeba3f4
AZ
2418 { "lock", NEED_RPC, 1, 1, do_lock_create },
2419 { "steal", NEED_RPC, 1, 1, do_lock_steal },
2420 { "unlock", NEED_RPC, 1, 1, do_lock_unlock },
53ffefe9
BP
2421 { "help", NEED_NONE, 0, INT_MAX, do_help },
2422
2423 { NULL, 0, 0, 0, NULL },
d0632593 2424};
3815d6c2
LS
2425
2426static const struct ovsdb_client_command *get_all_commands(void)
2427{
2428 return all_commands;
2429}