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