]> git.proxmox.com Git - mirror_ovs.git/blob - lib/db-ctl-base.c
db-ctl-base: remove the recurse member from struct cmd_show_table
[mirror_ovs.git] / lib / db-ctl-base.c
1 /*
2 * Copyright (c) 2015 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18
19 #include <ctype.h>
20 #include <getopt.h>
21 #include <unistd.h>
22
23 #include "db-ctl-base.h"
24
25 #include "command-line.h"
26 #include "compiler.h"
27 #include "dirs.h"
28 #include "dynamic-string.h"
29 #include "fatal-signal.h"
30 #include "hash.h"
31 #include "json.h"
32 #include "openvswitch/vlog.h"
33 #include "ovsdb-data.h"
34 #include "ovsdb-idl.h"
35 #include "ovsdb-idl-provider.h"
36 #include "shash.h"
37 #include "sset.h"
38 #include "string.h"
39 #include "table.h"
40 #include "util.h"
41
42 VLOG_DEFINE_THIS_MODULE(db_ctl_base);
43
44 /* This array defines the 'show' command output format. User can check the
45 * definition in utilities/ovs-vsctl.c as reference.
46 *
47 * Particularly, if an element in 'columns[]' represents a reference to
48 * another table, the referred table must also be defined as an entry in
49 * in 'cmd_show_tables[]'.
50 *
51 * The definition must end with an all-NULL entry. It is initalized once
52 * when ctl_init() is called.
53 *
54 * */
55 extern struct cmd_show_table cmd_show_tables[];
56
57 /* ctl_exit() is called by ctl_fatal(). User can optionally supply an exit
58 * function ctl_exit_func() via ctl_init. If supplied, this function will
59 * be called by ctl_exit()
60 */
61 static void (*ctl_exit_func)(int status) = NULL;
62 OVS_NO_RETURN static void ctl_exit(int status);
63
64 /* Represents all tables in the schema. User must define 'tables'
65 * in implementation and supply via clt_init(). The definition must end
66 * with an all-NULL entry. */
67 static const struct ctl_table_class *tables;
68
69 static struct shash all_commands = SHASH_INITIALIZER(&all_commands);
70 static const struct ctl_table_class *get_table(const char *table_name);
71 static void set_column(const struct ctl_table_class *,
72 const struct ovsdb_idl_row *, const char *,
73 struct ovsdb_symbol_table *);
74
75 \f
76 static struct option *
77 find_option(const char *name, struct option *options, size_t n_options)
78 {
79 size_t i;
80
81 for (i = 0; i < n_options; i++) {
82 if (!strcmp(options[i].name, name)) {
83 return &options[i];
84 }
85 }
86 return NULL;
87 }
88
89 static struct option *
90 add_option(struct option **optionsp, size_t *n_optionsp,
91 size_t *allocated_optionsp)
92 {
93 if (*n_optionsp >= *allocated_optionsp) {
94 *optionsp = x2nrealloc(*optionsp, allocated_optionsp,
95 sizeof **optionsp);
96 }
97 return &(*optionsp)[(*n_optionsp)++];
98 }
99
100 /* Converts the command arguments into format that can be parsed by
101 * bash completion script.
102 *
103 * Therein, arguments will be attached with following prefixes:
104 *
105 * !argument :: The argument is required
106 * ?argument :: The argument is optional
107 * *argument :: The argument may appear any number (0 or more) times
108 * +argument :: The argument may appear one or more times
109 *
110 */
111 static void
112 print_command_arguments(const struct ctl_command_syntax *command)
113 {
114 /*
115 * The argument string is parsed in reverse. We use a stack 'oew_stack' to
116 * keep track of nested optionals. Whenever a ']' is encountered, we push
117 * a bit to 'oew_stack'. The bit is set to 1 if the ']' is not nested.
118 * Subsequently, we pop an entry everytime '[' is met.
119 *
120 * We use 'whole_word_is_optional' value to decide whether or not a ! or +
121 * should be added on encountering a space: if the optional surrounds the
122 * whole word then it shouldn't be, but if it is only a part of the word
123 * (i.e. [key=]value), it should be.
124 */
125 uint32_t oew_stack = 0;
126
127 const char *arguments = command->arguments;
128 int length = strlen(arguments);
129 if (!length) {
130 return;
131 }
132
133 /* Output buffer, written backward from end. */
134 char *output = xmalloc(2 * length);
135 char *outp = output + 2 * length;
136 *--outp = '\0';
137
138 bool in_repeated = false;
139 bool whole_word_is_optional = false;
140
141 for (const char *inp = arguments + length; inp > arguments; ) {
142 switch (*--inp) {
143 case ']':
144 oew_stack <<= 1;
145 if (inp[1] == '\0' || inp[1] == ' ' || inp[1] == '.') {
146 oew_stack |= 1;
147 }
148 break;
149 case '[':
150 /* Checks if the whole word is optional, and sets the
151 * 'whole_word_is_optional' accordingly. */
152 if ((inp == arguments || inp[-1] == ' ') && oew_stack & 1) {
153 *--outp = in_repeated ? '*' : '?';
154 whole_word_is_optional = true;
155 } else {
156 *--outp = '?';
157 whole_word_is_optional = false;
158 }
159 oew_stack >>= 1;
160 break;
161 case ' ':
162 if (!whole_word_is_optional) {
163 *--outp = in_repeated ? '+' : '!';
164 }
165 *--outp = ' ';
166 in_repeated = false;
167 whole_word_is_optional = false;
168 break;
169 case '.':
170 in_repeated = true;
171 break;
172 default:
173 *--outp = *inp;
174 break;
175 }
176 }
177 if (arguments[0] != '[' && outp != output + 2 * length - 1) {
178 *--outp = in_repeated ? '+' : '!';
179 }
180 printf("%s", outp);
181 free(output);
182 }
183
184 static void
185 die_if_error(char *error)
186 {
187 if (error) {
188 ctl_fatal("%s", error);
189 }
190 }
191
192 static int
193 to_lower_and_underscores(unsigned c)
194 {
195 return c == '-' ? '_' : tolower(c);
196 }
197
198 static unsigned int
199 score_partial_match(const char *name, const char *s)
200 {
201 int score;
202
203 if (!strcmp(name, s)) {
204 return UINT_MAX;
205 }
206 for (score = 0; ; score++, name++, s++) {
207 if (to_lower_and_underscores(*name) != to_lower_and_underscores(*s)) {
208 break;
209 } else if (*name == '\0') {
210 return UINT_MAX - 1;
211 }
212 }
213 return *s == '\0' ? score : 0;
214 }
215
216 static struct ovsdb_symbol *
217 create_symbol(struct ovsdb_symbol_table *symtab, const char *id, bool *newp)
218 {
219 struct ovsdb_symbol *symbol;
220
221 if (id[0] != '@') {
222 ctl_fatal("row id \"%s\" does not begin with \"@\"", id);
223 }
224
225 if (newp) {
226 *newp = ovsdb_symbol_table_get(symtab, id) == NULL;
227 }
228
229 symbol = ovsdb_symbol_table_insert(symtab, id);
230 if (symbol->created) {
231 ctl_fatal("row id \"%s\" may only be specified on one --id option",
232 id);
233 }
234 symbol->created = true;
235 return symbol;
236 }
237
238 static const struct ovsdb_idl_row *
239 get_row_by_id(struct ctl_context *ctx, const struct ctl_table_class *table,
240 const struct ctl_row_id *id, const char *record_id)
241 {
242 const struct ovsdb_idl_row *referrer, *final;
243
244 if (!id->table) {
245 return NULL;
246 }
247
248 if (!id->name_column) {
249 if (strcmp(record_id, ".")) {
250 return NULL;
251 }
252 referrer = ovsdb_idl_first_row(ctx->idl, id->table);
253 if (!referrer || ovsdb_idl_next_row(referrer)) {
254 return NULL;
255 }
256 } else {
257 const struct ovsdb_idl_row *row;
258
259 referrer = NULL;
260 for (row = ovsdb_idl_first_row(ctx->idl, id->table);
261 row != NULL;
262 row = ovsdb_idl_next_row(row))
263 {
264 const struct ovsdb_datum *name;
265
266 name = ovsdb_idl_get(row, id->name_column,
267 OVSDB_TYPE_STRING, OVSDB_TYPE_VOID);
268 if (name->n == 1 && !strcmp(name->keys[0].string, record_id)) {
269 if (referrer) {
270 ctl_fatal("multiple rows in %s match \"%s\"",
271 table->class->name, record_id);
272 }
273 referrer = row;
274 }
275 }
276 }
277 if (!referrer) {
278 return NULL;
279 }
280
281 final = NULL;
282 if (id->uuid_column) {
283 const struct ovsdb_datum *uuid;
284
285 ovsdb_idl_txn_verify(referrer, id->uuid_column);
286 uuid = ovsdb_idl_get(referrer, id->uuid_column,
287 OVSDB_TYPE_UUID, OVSDB_TYPE_VOID);
288 if (uuid->n == 1) {
289 final = ovsdb_idl_get_row_for_uuid(ctx->idl, table->class,
290 &uuid->keys[0].uuid);
291 }
292 } else {
293 final = referrer;
294 }
295
296 return final;
297 }
298
299 static const struct ovsdb_idl_row *
300 get_row(struct ctl_context *ctx,
301 const struct ctl_table_class *table, const char *record_id,
302 bool must_exist)
303 {
304 const struct ovsdb_idl_row *row;
305 struct uuid uuid;
306
307 row = NULL;
308 if (uuid_from_string(&uuid, record_id)) {
309 row = ovsdb_idl_get_row_for_uuid(ctx->idl, table->class, &uuid);
310 }
311 if (!row) {
312 int i;
313
314 for (i = 0; i < ARRAY_SIZE(table->row_ids); i++) {
315 row = get_row_by_id(ctx, table, &table->row_ids[i], record_id);
316 if (row) {
317 break;
318 }
319 }
320 }
321 if (must_exist && !row) {
322 ctl_fatal("no row \"%s\" in table %s",
323 record_id, table->class->name);
324 }
325 return row;
326 }
327
328 static char *
329 get_column(const struct ctl_table_class *table, const char *column_name,
330 const struct ovsdb_idl_column **columnp)
331 {
332 const struct ovsdb_idl_column *best_match = NULL;
333 unsigned int best_score = 0;
334 size_t i;
335
336 for (i = 0; i < table->class->n_columns; i++) {
337 const struct ovsdb_idl_column *column = &table->class->columns[i];
338 unsigned int score = score_partial_match(column->name, column_name);
339 if (score > best_score) {
340 best_match = column;
341 best_score = score;
342 } else if (score == best_score) {
343 best_match = NULL;
344 }
345 }
346
347 *columnp = best_match;
348 if (best_match) {
349 return NULL;
350 } else if (best_score) {
351 return xasprintf("%s contains more than one column whose name "
352 "matches \"%s\"", table->class->name, column_name);
353 } else {
354 return xasprintf("%s does not contain a column whose name matches "
355 "\"%s\"", table->class->name, column_name);
356 }
357 }
358
359 static void
360 pre_get_column(struct ctl_context *ctx,
361 const struct ctl_table_class *table, const char *column_name,
362 const struct ovsdb_idl_column **columnp)
363 {
364 die_if_error(get_column(table, column_name, columnp));
365 ovsdb_idl_add_column(ctx->idl, *columnp);
366 }
367
368 static const struct ctl_table_class *
369 pre_get_table(struct ctl_context *ctx, const char *table_name)
370 {
371 const struct ctl_table_class *table_class;
372 int i;
373
374 table_class = get_table(table_name);
375 ovsdb_idl_add_table(ctx->idl, table_class->class);
376
377 for (i = 0; i < ARRAY_SIZE(table_class->row_ids); i++) {
378 const struct ctl_row_id *id = &table_class->row_ids[i];
379 if (id->table) {
380 ovsdb_idl_add_table(ctx->idl, id->table);
381 }
382 if (id->name_column) {
383 ovsdb_idl_add_column(ctx->idl, id->name_column);
384 }
385 if (id->uuid_column) {
386 ovsdb_idl_add_column(ctx->idl, id->uuid_column);
387 }
388 }
389
390 return table_class;
391 }
392
393 static char *
394 missing_operator_error(const char *arg, const char **allowed_operators,
395 size_t n_allowed)
396 {
397 struct ds s;
398
399 ds_init(&s);
400 ds_put_format(&s, "%s: argument does not end in ", arg);
401 ds_put_format(&s, "\"%s\"", allowed_operators[0]);
402 if (n_allowed == 2) {
403 ds_put_format(&s, " or \"%s\"", allowed_operators[1]);
404 } else if (n_allowed > 2) {
405 size_t i;
406
407 for (i = 1; i < n_allowed - 1; i++) {
408 ds_put_format(&s, ", \"%s\"", allowed_operators[i]);
409 }
410 ds_put_format(&s, ", or \"%s\"", allowed_operators[i]);
411 }
412 ds_put_format(&s, " followed by a value.");
413
414 return ds_steal_cstr(&s);
415 }
416
417 /* Breaks 'arg' apart into a number of fields in the following order:
418 *
419 * - The name of a column in 'table', stored into '*columnp'. The column
420 * name may be abbreviated.
421 *
422 * - Optionally ':' followed by a key string. The key is stored as a
423 * malloc()'d string into '*keyp', or NULL if no key is present in
424 * 'arg'.
425 *
426 * - If 'valuep' is nonnull, an operator followed by a value string. The
427 * allowed operators are the 'n_allowed' string in 'allowed_operators',
428 * or just "=" if 'n_allowed' is 0. If 'operatorp' is nonnull, then the
429 * index of the operator within 'allowed_operators' is stored into
430 * '*operatorp'. The value is stored as a malloc()'d string into
431 * '*valuep', or NULL if no value is present in 'arg'.
432 *
433 * On success, returns NULL. On failure, returned a malloc()'d string error
434 * message and stores NULL into all of the nonnull output arguments. */
435 static char * OVS_WARN_UNUSED_RESULT
436 parse_column_key_value(const char *arg,
437 const struct ctl_table_class *table,
438 const struct ovsdb_idl_column **columnp, char **keyp,
439 int *operatorp,
440 const char **allowed_operators, size_t n_allowed,
441 char **valuep)
442 {
443 const char *p = arg;
444 char *column_name;
445 char *error;
446
447 ovs_assert(!(operatorp && !valuep));
448 *keyp = NULL;
449 if (valuep) {
450 *valuep = NULL;
451 }
452
453 /* Parse column name. */
454 error = ovsdb_token_parse(&p, &column_name);
455 if (error) {
456 goto error;
457 }
458 if (column_name[0] == '\0') {
459 free(column_name);
460 error = xasprintf("%s: missing column name", arg);
461 goto error;
462 }
463 error = get_column(table, column_name, columnp);
464 free(column_name);
465 if (error) {
466 goto error;
467 }
468
469 /* Parse key string. */
470 if (*p == ':') {
471 p++;
472 error = ovsdb_token_parse(&p, keyp);
473 if (error) {
474 goto error;
475 }
476 }
477
478 /* Parse value string. */
479 if (valuep) {
480 size_t best_len;
481 size_t i;
482 int best;
483
484 if (!allowed_operators) {
485 static const char *equals = "=";
486 allowed_operators = &equals;
487 n_allowed = 1;
488 }
489
490 best = -1;
491 best_len = 0;
492 for (i = 0; i < n_allowed; i++) {
493 const char *op = allowed_operators[i];
494 size_t op_len = strlen(op);
495
496 if (op_len > best_len && !strncmp(op, p, op_len) && p[op_len]) {
497 best_len = op_len;
498 best = i;
499 }
500 }
501 if (best < 0) {
502 error = missing_operator_error(arg, allowed_operators, n_allowed);
503 goto error;
504 }
505
506 if (operatorp) {
507 *operatorp = best;
508 }
509 *valuep = xstrdup(p + best_len);
510 } else {
511 if (*p != '\0') {
512 error = xasprintf("%s: trailing garbage \"%s\" in argument",
513 arg, p);
514 goto error;
515 }
516 }
517 return NULL;
518
519 error:
520 *columnp = NULL;
521 free(*keyp);
522 *keyp = NULL;
523 if (valuep) {
524 free(*valuep);
525 *valuep = NULL;
526 if (operatorp) {
527 *operatorp = -1;
528 }
529 }
530 return error;
531 }
532
533 static const struct ovsdb_idl_column *
534 pre_parse_column_key_value(struct ctl_context *ctx,
535 const char *arg,
536 const struct ctl_table_class *table)
537 {
538 const struct ovsdb_idl_column *column;
539 const char *p;
540 char *column_name;
541
542 p = arg;
543 die_if_error(ovsdb_token_parse(&p, &column_name));
544 if (column_name[0] == '\0') {
545 ctl_fatal("%s: missing column name", arg);
546 }
547
548 pre_get_column(ctx, table, column_name, &column);
549 free(column_name);
550
551 return column;
552 }
553
554 static void
555 check_mutable(const struct ovsdb_idl_row *row,
556 const struct ovsdb_idl_column *column)
557 {
558 if (!ovsdb_idl_is_mutable(row, column)) {
559 ctl_fatal("cannot modify read-only column %s in table %s",
560 column->name, row->table->class->name);
561 }
562 }
563
564 #define RELOPS \
565 RELOP(RELOP_EQ, "=") \
566 RELOP(RELOP_NE, "!=") \
567 RELOP(RELOP_LT, "<") \
568 RELOP(RELOP_GT, ">") \
569 RELOP(RELOP_LE, "<=") \
570 RELOP(RELOP_GE, ">=") \
571 RELOP(RELOP_SET_EQ, "{=}") \
572 RELOP(RELOP_SET_NE, "{!=}") \
573 RELOP(RELOP_SET_LT, "{<}") \
574 RELOP(RELOP_SET_GT, "{>}") \
575 RELOP(RELOP_SET_LE, "{<=}") \
576 RELOP(RELOP_SET_GE, "{>=}")
577
578 enum relop {
579 #define RELOP(ENUM, STRING) ENUM,
580 RELOPS
581 #undef RELOP
582 };
583
584 static bool
585 is_set_operator(enum relop op)
586 {
587 return (op == RELOP_SET_EQ || op == RELOP_SET_NE ||
588 op == RELOP_SET_LT || op == RELOP_SET_GT ||
589 op == RELOP_SET_LE || op == RELOP_SET_GE);
590 }
591
592 static bool
593 evaluate_relop(const struct ovsdb_datum *a, const struct ovsdb_datum *b,
594 const struct ovsdb_type *type, enum relop op)
595 {
596 switch (op) {
597 case RELOP_EQ:
598 case RELOP_SET_EQ:
599 return ovsdb_datum_compare_3way(a, b, type) == 0;
600 case RELOP_NE:
601 case RELOP_SET_NE:
602 return ovsdb_datum_compare_3way(a, b, type) != 0;
603 case RELOP_LT:
604 return ovsdb_datum_compare_3way(a, b, type) < 0;
605 case RELOP_GT:
606 return ovsdb_datum_compare_3way(a, b, type) > 0;
607 case RELOP_LE:
608 return ovsdb_datum_compare_3way(a, b, type) <= 0;
609 case RELOP_GE:
610 return ovsdb_datum_compare_3way(a, b, type) >= 0;
611
612 case RELOP_SET_LT:
613 return b->n > a->n && ovsdb_datum_includes_all(a, b, type);
614 case RELOP_SET_GT:
615 return a->n > b->n && ovsdb_datum_includes_all(b, a, type);
616 case RELOP_SET_LE:
617 return ovsdb_datum_includes_all(a, b, type);
618 case RELOP_SET_GE:
619 return ovsdb_datum_includes_all(b, a, type);
620
621 default:
622 OVS_NOT_REACHED();
623 }
624 }
625
626 static bool
627 is_condition_satisfied(const struct ctl_table_class *table,
628 const struct ovsdb_idl_row *row, const char *arg,
629 struct ovsdb_symbol_table *symtab)
630 {
631 static const char *operators[] = {
632 #define RELOP(ENUM, STRING) STRING,
633 RELOPS
634 #undef RELOP
635 };
636
637 const struct ovsdb_idl_column *column;
638 const struct ovsdb_datum *have_datum;
639 char *key_string, *value_string;
640 struct ovsdb_type type;
641 int operator;
642 bool retval;
643 char *error;
644
645 error = parse_column_key_value(arg, table, &column, &key_string,
646 &operator, operators, ARRAY_SIZE(operators),
647 &value_string);
648 die_if_error(error);
649 if (!value_string) {
650 ctl_fatal("%s: missing value", arg);
651 }
652
653 type = column->type;
654 type.n_max = UINT_MAX;
655
656 have_datum = ovsdb_idl_read(row, column);
657 if (key_string) {
658 union ovsdb_atom want_key;
659 struct ovsdb_datum b;
660 unsigned int idx;
661
662 if (column->type.value.type == OVSDB_TYPE_VOID) {
663 ctl_fatal("cannot specify key to check for non-map column %s",
664 column->name);
665 }
666
667 die_if_error(ovsdb_atom_from_string(&want_key, &column->type.key,
668 key_string, symtab));
669
670 type.key = type.value;
671 type.value.type = OVSDB_TYPE_VOID;
672 die_if_error(ovsdb_datum_from_string(&b, &type, value_string, symtab));
673
674 idx = ovsdb_datum_find_key(have_datum,
675 &want_key, column->type.key.type);
676 if (idx == UINT_MAX && !is_set_operator(operator)) {
677 retval = false;
678 } else {
679 struct ovsdb_datum a;
680
681 if (idx != UINT_MAX) {
682 a.n = 1;
683 a.keys = &have_datum->values[idx];
684 a.values = NULL;
685 } else {
686 a.n = 0;
687 a.keys = NULL;
688 a.values = NULL;
689 }
690
691 retval = evaluate_relop(&a, &b, &type, operator);
692 }
693
694 ovsdb_atom_destroy(&want_key, column->type.key.type);
695 ovsdb_datum_destroy(&b, &type);
696 } else {
697 struct ovsdb_datum want_datum;
698
699 die_if_error(ovsdb_datum_from_string(&want_datum, &column->type,
700 value_string, symtab));
701 retval = evaluate_relop(have_datum, &want_datum, &type, operator);
702 ovsdb_datum_destroy(&want_datum, &column->type);
703 }
704
705 free(key_string);
706 free(value_string);
707
708 return retval;
709 }
710
711 static void
712 invalidate_cache(struct ctl_context *ctx)
713 {
714 if (ctx->invalidate_cache) {
715 (ctx->invalidate_cache)(ctx);
716 }
717 }
718 \f
719 static void
720 pre_cmd_get(struct ctl_context *ctx)
721 {
722 const char *id = shash_find_data(&ctx->options, "--id");
723 const char *table_name = ctx->argv[1];
724 const struct ctl_table_class *table;
725 int i;
726
727 /* Using "get" without --id or a column name could possibly make sense.
728 * Maybe, for example, a *ctl command run wants to assert that a row
729 * exists. But it is unlikely that an interactive user would want to do
730 * that, so issue a warning if we're running on a terminal. */
731 if (!id && ctx->argc <= 3 && isatty(STDOUT_FILENO)) {
732 VLOG_WARN("\"get\" command without row arguments or \"--id\" is "
733 "possibly erroneous");
734 }
735
736 table = pre_get_table(ctx, table_name);
737 for (i = 3; i < ctx->argc; i++) {
738 if (!strcasecmp(ctx->argv[i], "_uuid")
739 || !strcasecmp(ctx->argv[i], "-uuid")) {
740 continue;
741 }
742
743 pre_parse_column_key_value(ctx, ctx->argv[i], table);
744 }
745 }
746
747 static void
748 cmd_get(struct ctl_context *ctx)
749 {
750 const char *id = shash_find_data(&ctx->options, "--id");
751 bool must_exist = !shash_find(&ctx->options, "--if-exists");
752 const char *table_name = ctx->argv[1];
753 const char *record_id = ctx->argv[2];
754 const struct ctl_table_class *table;
755 const struct ovsdb_idl_row *row;
756 struct ds *out = &ctx->output;
757 int i;
758
759 if (id && !must_exist) {
760 ctl_fatal("--if-exists and --id may not be specified together");
761 }
762
763 table = get_table(table_name);
764 row = get_row(ctx, table, record_id, must_exist);
765 if (!row) {
766 return;
767 }
768
769 if (id) {
770 struct ovsdb_symbol *symbol;
771 bool new;
772
773 symbol = create_symbol(ctx->symtab, id, &new);
774 if (!new) {
775 ctl_fatal("row id \"%s\" specified on \"get\" command was used "
776 "before it was defined", id);
777 }
778 symbol->uuid = row->uuid;
779
780 /* This symbol refers to a row that already exists, so disable warnings
781 * about it being unreferenced. */
782 symbol->strong_ref = true;
783 }
784 for (i = 3; i < ctx->argc; i++) {
785 const struct ovsdb_idl_column *column;
786 const struct ovsdb_datum *datum;
787 char *key_string;
788
789 /* Special case for obtaining the UUID of a row. We can't just do this
790 * through parse_column_key_value() below since it returns a "struct
791 * ovsdb_idl_column" and the UUID column doesn't have one. */
792 if (!strcasecmp(ctx->argv[i], "_uuid")
793 || !strcasecmp(ctx->argv[i], "-uuid")) {
794 ds_put_format(out, UUID_FMT"\n", UUID_ARGS(&row->uuid));
795 continue;
796 }
797
798 die_if_error(parse_column_key_value(ctx->argv[i], table,
799 &column, &key_string,
800 NULL, NULL, 0, NULL));
801
802 ovsdb_idl_txn_verify(row, column);
803 datum = ovsdb_idl_read(row, column);
804 if (key_string) {
805 union ovsdb_atom key;
806 unsigned int idx;
807
808 if (column->type.value.type == OVSDB_TYPE_VOID) {
809 ctl_fatal("cannot specify key to get for non-map column %s",
810 column->name);
811 }
812
813 die_if_error(ovsdb_atom_from_string(&key,
814 &column->type.key,
815 key_string, ctx->symtab));
816
817 idx = ovsdb_datum_find_key(datum, &key,
818 column->type.key.type);
819 if (idx == UINT_MAX) {
820 if (must_exist) {
821 ctl_fatal("no key \"%s\" in %s record \"%s\" column %s",
822 key_string, table->class->name, record_id,
823 column->name);
824 }
825 } else {
826 ovsdb_atom_to_string(&datum->values[idx],
827 column->type.value.type, out);
828 }
829 ovsdb_atom_destroy(&key, column->type.key.type);
830 } else {
831 ovsdb_datum_to_string(datum, &column->type, out);
832 }
833 ds_put_char(out, '\n');
834
835 free(key_string);
836 }
837 }
838
839 static void
840 parse_column_names(const char *column_names,
841 const struct ctl_table_class *table,
842 const struct ovsdb_idl_column ***columnsp,
843 size_t *n_columnsp)
844 {
845 const struct ovsdb_idl_column **columns;
846 size_t n_columns;
847
848 if (!column_names) {
849 size_t i;
850
851 n_columns = table->class->n_columns + 1;
852 columns = xmalloc(n_columns * sizeof *columns);
853 columns[0] = NULL;
854 for (i = 0; i < table->class->n_columns; i++) {
855 columns[i + 1] = &table->class->columns[i];
856 }
857 } else {
858 char *s = xstrdup(column_names);
859 size_t allocated_columns;
860 char *save_ptr = NULL;
861 char *column_name;
862
863 columns = NULL;
864 allocated_columns = n_columns = 0;
865 for (column_name = strtok_r(s, ", ", &save_ptr); column_name;
866 column_name = strtok_r(NULL, ", ", &save_ptr)) {
867 const struct ovsdb_idl_column *column;
868
869 if (!strcasecmp(column_name, "_uuid")) {
870 column = NULL;
871 } else {
872 die_if_error(get_column(table, column_name, &column));
873 }
874 if (n_columns >= allocated_columns) {
875 columns = x2nrealloc(columns, &allocated_columns,
876 sizeof *columns);
877 }
878 columns[n_columns++] = column;
879 }
880 free(s);
881
882 if (!n_columns) {
883 ctl_fatal("must specify at least one column name");
884 }
885 }
886 *columnsp = columns;
887 *n_columnsp = n_columns;
888 }
889
890 static void
891 pre_list_columns(struct ctl_context *ctx,
892 const struct ctl_table_class *table,
893 const char *column_names)
894 {
895 const struct ovsdb_idl_column **columns;
896 size_t n_columns;
897 size_t i;
898
899 parse_column_names(column_names, table, &columns, &n_columns);
900 for (i = 0; i < n_columns; i++) {
901 if (columns[i]) {
902 ovsdb_idl_add_column(ctx->idl, columns[i]);
903 }
904 }
905 free(columns);
906 }
907
908 static void
909 pre_cmd_list(struct ctl_context *ctx)
910 {
911 const char *column_names = shash_find_data(&ctx->options, "--columns");
912 const char *table_name = ctx->argv[1];
913 const struct ctl_table_class *table;
914
915 table = pre_get_table(ctx, table_name);
916 pre_list_columns(ctx, table, column_names);
917 }
918
919 static struct table *
920 list_make_table(const struct ovsdb_idl_column **columns, size_t n_columns)
921 {
922 struct table *out;
923 size_t i;
924
925 out = xmalloc(sizeof *out);
926 table_init(out);
927
928 for (i = 0; i < n_columns; i++) {
929 const struct ovsdb_idl_column *column = columns[i];
930 const char *column_name = column ? column->name : "_uuid";
931
932 table_add_column(out, "%s", column_name);
933 }
934
935 return out;
936 }
937
938 static void
939 list_record(const struct ovsdb_idl_row *row,
940 const struct ovsdb_idl_column **columns, size_t n_columns,
941 struct table *out)
942 {
943 size_t i;
944
945 if (!row) {
946 return;
947 }
948
949 table_add_row(out);
950 for (i = 0; i < n_columns; i++) {
951 const struct ovsdb_idl_column *column = columns[i];
952 struct cell *cell = table_add_cell(out);
953
954 if (!column) {
955 struct ovsdb_datum datum;
956 union ovsdb_atom atom;
957
958 atom.uuid = row->uuid;
959
960 datum.keys = &atom;
961 datum.values = NULL;
962 datum.n = 1;
963
964 cell->json = ovsdb_datum_to_json(&datum, &ovsdb_type_uuid);
965 cell->type = &ovsdb_type_uuid;
966 } else {
967 const struct ovsdb_datum *datum = ovsdb_idl_read(row, column);
968
969 cell->json = ovsdb_datum_to_json(datum, &column->type);
970 cell->type = &column->type;
971 }
972 }
973 }
974
975 static void
976 cmd_list(struct ctl_context *ctx)
977 {
978 const char *column_names = shash_find_data(&ctx->options, "--columns");
979 bool must_exist = !shash_find(&ctx->options, "--if-exists");
980 const struct ovsdb_idl_column **columns;
981 const char *table_name = ctx->argv[1];
982 const struct ctl_table_class *table;
983 struct table *out;
984 size_t n_columns;
985 int i;
986
987 table = get_table(table_name);
988 parse_column_names(column_names, table, &columns, &n_columns);
989 out = ctx->table = list_make_table(columns, n_columns);
990 if (ctx->argc > 2) {
991 for (i = 2; i < ctx->argc; i++) {
992 list_record(get_row(ctx, table, ctx->argv[i], must_exist),
993 columns, n_columns, out);
994 }
995 } else {
996 const struct ovsdb_idl_row *row;
997
998 for (row = ovsdb_idl_first_row(ctx->idl, table->class); row != NULL;
999 row = ovsdb_idl_next_row(row)) {
1000 list_record(row, columns, n_columns, out);
1001 }
1002 }
1003 free(columns);
1004 }
1005
1006 /* Finds and returns the "struct ctl_table_class *" with 'table_name' by
1007 * searching the 'tables'. */
1008 static const struct ctl_table_class *
1009 get_table(const char *table_name)
1010 {
1011 const struct ctl_table_class *table;
1012 const struct ctl_table_class *best_match = NULL;
1013 unsigned int best_score = 0;
1014
1015 for (table = tables; table->class; table++) {
1016 unsigned int score = score_partial_match(table->class->name,
1017 table_name);
1018 if (score > best_score) {
1019 best_match = table;
1020 best_score = score;
1021 } else if (score == best_score) {
1022 best_match = NULL;
1023 }
1024 }
1025 if (best_match) {
1026 return best_match;
1027 } else if (best_score) {
1028 ctl_fatal("multiple table names match \"%s\"", table_name);
1029 } else {
1030 ctl_fatal("unknown table \"%s\"", table_name);
1031 }
1032 return NULL;
1033 }
1034
1035 static void
1036 pre_cmd_find(struct ctl_context *ctx)
1037 {
1038 const char *column_names = shash_find_data(&ctx->options, "--columns");
1039 const char *table_name = ctx->argv[1];
1040 const struct ctl_table_class *table;
1041 int i;
1042
1043 table = pre_get_table(ctx, table_name);
1044 pre_list_columns(ctx, table, column_names);
1045 for (i = 2; i < ctx->argc; i++) {
1046 pre_parse_column_key_value(ctx, ctx->argv[i], table);
1047 }
1048 }
1049
1050 static void
1051 cmd_find(struct ctl_context *ctx)
1052 {
1053 const char *column_names = shash_find_data(&ctx->options, "--columns");
1054 const struct ovsdb_idl_column **columns;
1055 const char *table_name = ctx->argv[1];
1056 const struct ctl_table_class *table;
1057 const struct ovsdb_idl_row *row;
1058 struct table *out;
1059 size_t n_columns;
1060
1061 table = get_table(table_name);
1062 parse_column_names(column_names, table, &columns, &n_columns);
1063 out = ctx->table = list_make_table(columns, n_columns);
1064 for (row = ovsdb_idl_first_row(ctx->idl, table->class); row;
1065 row = ovsdb_idl_next_row(row)) {
1066 int i;
1067
1068 for (i = 2; i < ctx->argc; i++) {
1069 if (!is_condition_satisfied(table, row, ctx->argv[i],
1070 ctx->symtab)) {
1071 goto next_row;
1072 }
1073 }
1074 list_record(row, columns, n_columns, out);
1075
1076 next_row: ;
1077 }
1078 free(columns);
1079 }
1080
1081 /* Sets the column of 'row' in 'table'. */
1082 static void
1083 set_column(const struct ctl_table_class *table,
1084 const struct ovsdb_idl_row *row, const char *arg,
1085 struct ovsdb_symbol_table *symtab)
1086 {
1087 const struct ovsdb_idl_column *column;
1088 char *key_string, *value_string;
1089 char *error;
1090
1091 error = parse_column_key_value(arg, table, &column, &key_string,
1092 NULL, NULL, 0, &value_string);
1093 die_if_error(error);
1094 if (!value_string) {
1095 ctl_fatal("%s: missing value", arg);
1096 }
1097 check_mutable(row, column);
1098
1099 if (key_string) {
1100 union ovsdb_atom key, value;
1101 struct ovsdb_datum datum;
1102
1103 if (column->type.value.type == OVSDB_TYPE_VOID) {
1104 ctl_fatal("cannot specify key to set for non-map column %s",
1105 column->name);
1106 }
1107
1108 die_if_error(ovsdb_atom_from_string(&key, &column->type.key,
1109 key_string, symtab));
1110 die_if_error(ovsdb_atom_from_string(&value, &column->type.value,
1111 value_string, symtab));
1112
1113 ovsdb_datum_init_empty(&datum);
1114 ovsdb_datum_add_unsafe(&datum, &key, &value, &column->type);
1115
1116 ovsdb_atom_destroy(&key, column->type.key.type);
1117 ovsdb_atom_destroy(&value, column->type.value.type);
1118
1119 ovsdb_datum_union(&datum, ovsdb_idl_read(row, column),
1120 &column->type, false);
1121 ovsdb_idl_txn_verify(row, column);
1122 ovsdb_idl_txn_write(row, column, &datum);
1123 } else {
1124 struct ovsdb_datum datum;
1125
1126 die_if_error(ovsdb_datum_from_string(&datum, &column->type,
1127 value_string, symtab));
1128 ovsdb_idl_txn_write(row, column, &datum);
1129 }
1130
1131 free(key_string);
1132 free(value_string);
1133 }
1134
1135 static void
1136 pre_cmd_set(struct ctl_context *ctx)
1137 {
1138 const char *table_name = ctx->argv[1];
1139 const struct ctl_table_class *table;
1140 int i;
1141
1142 table = pre_get_table(ctx, table_name);
1143 for (i = 3; i < ctx->argc; i++) {
1144 pre_parse_column_key_value(ctx, ctx->argv[i], table);
1145 }
1146 }
1147
1148 static void
1149 cmd_set(struct ctl_context *ctx)
1150 {
1151 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1152 const char *table_name = ctx->argv[1];
1153 const char *record_id = ctx->argv[2];
1154 const struct ctl_table_class *table;
1155 const struct ovsdb_idl_row *row;
1156 int i;
1157
1158 table = get_table(table_name);
1159 row = get_row(ctx, table, record_id, must_exist);
1160 if (!row) {
1161 return;
1162 }
1163
1164 for (i = 3; i < ctx->argc; i++) {
1165 set_column(table, row, ctx->argv[i], ctx->symtab);
1166 }
1167
1168 invalidate_cache(ctx);
1169 }
1170
1171 static void
1172 pre_cmd_add(struct ctl_context *ctx)
1173 {
1174 const char *table_name = ctx->argv[1];
1175 const char *column_name = ctx->argv[3];
1176 const struct ctl_table_class *table;
1177 const struct ovsdb_idl_column *column;
1178
1179 table = pre_get_table(ctx, table_name);
1180 pre_get_column(ctx, table, column_name, &column);
1181 }
1182
1183 static void
1184 cmd_add(struct ctl_context *ctx)
1185 {
1186 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1187 const char *table_name = ctx->argv[1];
1188 const char *record_id = ctx->argv[2];
1189 const char *column_name = ctx->argv[3];
1190 const struct ctl_table_class *table;
1191 const struct ovsdb_idl_column *column;
1192 const struct ovsdb_idl_row *row;
1193 const struct ovsdb_type *type;
1194 struct ovsdb_datum old;
1195 int i;
1196
1197 table = get_table(table_name);
1198 die_if_error(get_column(table, column_name, &column));
1199 row = get_row(ctx, table, record_id, must_exist);
1200 if (!row) {
1201 return;
1202 }
1203 check_mutable(row, column);
1204
1205 type = &column->type;
1206 ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type);
1207 for (i = 4; i < ctx->argc; i++) {
1208 struct ovsdb_type add_type;
1209 struct ovsdb_datum add;
1210
1211 add_type = *type;
1212 add_type.n_min = 1;
1213 add_type.n_max = UINT_MAX;
1214 die_if_error(ovsdb_datum_from_string(&add, &add_type, ctx->argv[i],
1215 ctx->symtab));
1216 ovsdb_datum_union(&old, &add, type, false);
1217 ovsdb_datum_destroy(&add, type);
1218 }
1219 if (old.n > type->n_max) {
1220 ctl_fatal("\"add\" operation would put %u %s in column %s of "
1221 "table %s but the maximum number is %u",
1222 old.n,
1223 type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs",
1224 column->name, table->class->name, type->n_max);
1225 }
1226 ovsdb_idl_txn_verify(row, column);
1227 ovsdb_idl_txn_write(row, column, &old);
1228
1229 invalidate_cache(ctx);
1230 }
1231
1232 static void
1233 pre_cmd_remove(struct ctl_context *ctx)
1234 {
1235 const char *table_name = ctx->argv[1];
1236 const char *column_name = ctx->argv[3];
1237 const struct ctl_table_class *table;
1238 const struct ovsdb_idl_column *column;
1239
1240 table = pre_get_table(ctx, table_name);
1241 pre_get_column(ctx, table, column_name, &column);
1242 }
1243
1244 static void
1245 cmd_remove(struct ctl_context *ctx)
1246 {
1247 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1248 const char *table_name = ctx->argv[1];
1249 const char *record_id = ctx->argv[2];
1250 const char *column_name = ctx->argv[3];
1251 const struct ctl_table_class *table;
1252 const struct ovsdb_idl_column *column;
1253 const struct ovsdb_idl_row *row;
1254 const struct ovsdb_type *type;
1255 struct ovsdb_datum old;
1256 int i;
1257
1258 table = get_table(table_name);
1259 die_if_error(get_column(table, column_name, &column));
1260 row = get_row(ctx, table, record_id, must_exist);
1261 if (!row) {
1262 return;
1263 }
1264 check_mutable(row, column);
1265
1266 type = &column->type;
1267 ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type);
1268 for (i = 4; i < ctx->argc; i++) {
1269 struct ovsdb_type rm_type;
1270 struct ovsdb_datum rm;
1271 char *error;
1272
1273 rm_type = *type;
1274 rm_type.n_min = 1;
1275 rm_type.n_max = UINT_MAX;
1276 error = ovsdb_datum_from_string(&rm, &rm_type,
1277 ctx->argv[i], ctx->symtab);
1278
1279 if (error) {
1280 if (ovsdb_type_is_map(&rm_type)) {
1281 rm_type.value.type = OVSDB_TYPE_VOID;
1282 free(error);
1283 die_if_error(ovsdb_datum_from_string(
1284 &rm, &rm_type, ctx->argv[i], ctx->symtab));
1285 } else {
1286 ctl_fatal("%s", error);
1287 }
1288 }
1289 ovsdb_datum_subtract(&old, type, &rm, &rm_type);
1290 ovsdb_datum_destroy(&rm, &rm_type);
1291 }
1292 if (old.n < type->n_min) {
1293 ctl_fatal("\"remove\" operation would put %u %s in column %s of "
1294 "table %s but the minimum number is %u",
1295 old.n,
1296 type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs",
1297 column->name, table->class->name, type->n_min);
1298 }
1299 ovsdb_idl_txn_verify(row, column);
1300 ovsdb_idl_txn_write(row, column, &old);
1301
1302 invalidate_cache(ctx);
1303 }
1304
1305 static void
1306 pre_cmd_clear(struct ctl_context *ctx)
1307 {
1308 const char *table_name = ctx->argv[1];
1309 const struct ctl_table_class *table;
1310 int i;
1311
1312 table = pre_get_table(ctx, table_name);
1313 for (i = 3; i < ctx->argc; i++) {
1314 const struct ovsdb_idl_column *column;
1315
1316 pre_get_column(ctx, table, ctx->argv[i], &column);
1317 }
1318 }
1319
1320 static void
1321 cmd_clear(struct ctl_context *ctx)
1322 {
1323 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1324 const char *table_name = ctx->argv[1];
1325 const char *record_id = ctx->argv[2];
1326 const struct ctl_table_class *table;
1327 const struct ovsdb_idl_row *row;
1328 int i;
1329
1330 table = get_table(table_name);
1331 row = get_row(ctx, table, record_id, must_exist);
1332 if (!row) {
1333 return;
1334 }
1335
1336 for (i = 3; i < ctx->argc; i++) {
1337 const struct ovsdb_idl_column *column;
1338 const struct ovsdb_type *type;
1339 struct ovsdb_datum datum;
1340
1341 die_if_error(get_column(table, ctx->argv[i], &column));
1342 check_mutable(row, column);
1343
1344 type = &column->type;
1345 if (type->n_min > 0) {
1346 ctl_fatal("\"clear\" operation cannot be applied to column %s "
1347 "of table %s, which is not allowed to be empty",
1348 column->name, table->class->name);
1349 }
1350
1351 ovsdb_datum_init_empty(&datum);
1352 ovsdb_idl_txn_write(row, column, &datum);
1353 }
1354
1355 invalidate_cache(ctx);
1356 }
1357
1358 static void
1359 pre_create(struct ctl_context *ctx)
1360 {
1361 const char *id = shash_find_data(&ctx->options, "--id");
1362 const char *table_name = ctx->argv[1];
1363 const struct ctl_table_class *table;
1364
1365 table = get_table(table_name);
1366 if (!id && !table->class->is_root) {
1367 VLOG_WARN("applying \"create\" command to table %s without --id "
1368 "option will have no effect", table->class->name);
1369 }
1370 }
1371
1372 static void
1373 cmd_create(struct ctl_context *ctx)
1374 {
1375 const char *id = shash_find_data(&ctx->options, "--id");
1376 const char *table_name = ctx->argv[1];
1377 const struct ctl_table_class *table = get_table(table_name);
1378 const struct ovsdb_idl_row *row;
1379 const struct uuid *uuid;
1380 int i;
1381
1382 if (id) {
1383 struct ovsdb_symbol *symbol = create_symbol(ctx->symtab, id, NULL);
1384 if (table->class->is_root) {
1385 /* This table is in the root set, meaning that rows created in it
1386 * won't disappear even if they are unreferenced, so disable
1387 * warnings about that by pretending that there is a reference. */
1388 symbol->strong_ref = true;
1389 }
1390 uuid = &symbol->uuid;
1391 } else {
1392 uuid = NULL;
1393 }
1394
1395 row = ovsdb_idl_txn_insert(ctx->txn, table->class, uuid);
1396 for (i = 2; i < ctx->argc; i++) {
1397 set_column(table, row, ctx->argv[i], ctx->symtab);
1398 }
1399 ds_put_format(&ctx->output, UUID_FMT, UUID_ARGS(&row->uuid));
1400 }
1401
1402 /* This function may be used as the 'postprocess' function for commands that
1403 * insert new rows into the database. It expects that the command's 'run'
1404 * function prints the UUID reported by ovsdb_idl_txn_insert() as the command's
1405 * sole output. It replaces that output by the row's permanent UUID assigned
1406 * by the database server and appends a new-line.
1407 *
1408 * Currently we use this only for "create", because the higher-level commands
1409 * are supposed to be independent of the actual structure of the vswitch
1410 * configuration. */
1411 static void
1412 post_create(struct ctl_context *ctx)
1413 {
1414 const struct uuid *real;
1415 struct uuid dummy;
1416
1417 if (!uuid_from_string(&dummy, ds_cstr(&ctx->output))) {
1418 OVS_NOT_REACHED();
1419 }
1420 real = ovsdb_idl_txn_get_insert_uuid(ctx->txn, &dummy);
1421 if (real) {
1422 ds_clear(&ctx->output);
1423 ds_put_format(&ctx->output, UUID_FMT, UUID_ARGS(real));
1424 }
1425 ds_put_char(&ctx->output, '\n');
1426 }
1427
1428 static void
1429 pre_cmd_destroy(struct ctl_context *ctx)
1430 {
1431 const char *table_name = ctx->argv[1];
1432
1433 pre_get_table(ctx, table_name);
1434 }
1435
1436 static void
1437 cmd_destroy(struct ctl_context *ctx)
1438 {
1439 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1440 bool delete_all = shash_find(&ctx->options, "--all");
1441 const char *table_name = ctx->argv[1];
1442 const struct ctl_table_class *table;
1443 int i;
1444
1445 table = get_table(table_name);
1446
1447 if (delete_all && ctx->argc > 2) {
1448 ctl_fatal("--all and records argument should not be specified together");
1449 }
1450
1451 if (delete_all && !must_exist) {
1452 ctl_fatal("--all and --if-exists should not be specified together");
1453 }
1454
1455 if (delete_all) {
1456 const struct ovsdb_idl_row *row;
1457 const struct ovsdb_idl_row *next_row;
1458
1459 for (row = ovsdb_idl_first_row(ctx->idl, table->class);
1460 row;) {
1461 next_row = ovsdb_idl_next_row(row);
1462 ovsdb_idl_txn_delete(row);
1463 row = next_row;
1464 }
1465 } else {
1466 for (i = 2; i < ctx->argc; i++) {
1467 const struct ovsdb_idl_row *row;
1468
1469 row = get_row(ctx, table, ctx->argv[i], must_exist);
1470 if (row) {
1471 ovsdb_idl_txn_delete(row);
1472 }
1473 }
1474 }
1475 invalidate_cache(ctx);
1476 }
1477
1478 static void
1479 pre_cmd_wait_until(struct ctl_context *ctx)
1480 {
1481 const char *table_name = ctx->argv[1];
1482 const struct ctl_table_class *table;
1483 int i;
1484
1485 table = pre_get_table(ctx, table_name);
1486
1487 for (i = 3; i < ctx->argc; i++) {
1488 pre_parse_column_key_value(ctx, ctx->argv[i], table);
1489 }
1490 }
1491
1492 static void
1493 cmd_wait_until(struct ctl_context *ctx)
1494 {
1495 const char *table_name = ctx->argv[1];
1496 const char *record_id = ctx->argv[2];
1497 const struct ctl_table_class *table;
1498 const struct ovsdb_idl_row *row;
1499 int i;
1500
1501 table = get_table(table_name);
1502
1503 row = get_row(ctx, table, record_id, false);
1504 if (!row) {
1505 ctx->try_again = true;
1506 return;
1507 }
1508
1509 for (i = 3; i < ctx->argc; i++) {
1510 if (!is_condition_satisfied(table, row, ctx->argv[i], ctx->symtab)) {
1511 ctx->try_again = true;
1512 return;
1513 }
1514 }
1515 }
1516
1517 /* Parses one command. */
1518 static void
1519 parse_command(int argc, char *argv[], struct shash *local_options,
1520 struct ctl_command *command)
1521 {
1522 const struct ctl_command_syntax *p;
1523 struct shash_node *node;
1524 int n_arg;
1525 int i;
1526
1527 shash_init(&command->options);
1528 shash_swap(local_options, &command->options);
1529 for (i = 0; i < argc; i++) {
1530 const char *option = argv[i];
1531 const char *equals;
1532 char *key, *value;
1533
1534 if (option[0] != '-') {
1535 break;
1536 }
1537
1538 equals = strchr(option, '=');
1539 if (equals) {
1540 key = xmemdup0(option, equals - option);
1541 value = xstrdup(equals + 1);
1542 } else {
1543 key = xstrdup(option);
1544 value = NULL;
1545 }
1546
1547 if (shash_find(&command->options, key)) {
1548 ctl_fatal("'%s' option specified multiple times", argv[i]);
1549 }
1550 shash_add_nocopy(&command->options, key, value);
1551 }
1552 if (i == argc) {
1553 ctl_fatal("missing command name (use --help for help)");
1554 }
1555
1556 p = shash_find_data(&all_commands, argv[i]);
1557 if (!p) {
1558 ctl_fatal("unknown command '%s'; use --help for help", argv[i]);
1559 }
1560
1561 SHASH_FOR_EACH (node, &command->options) {
1562 const char *s = strstr(p->options, node->name);
1563 int end = s ? s[strlen(node->name)] : EOF;
1564
1565 if (end != '=' && end != ',' && end != ' ' && end != '\0') {
1566 ctl_fatal("'%s' command has no '%s' option",
1567 argv[i], node->name);
1568 }
1569 if ((end == '=') != (node->data != NULL)) {
1570 if (end == '=') {
1571 ctl_fatal("missing argument to '%s' option on '%s' "
1572 "command", node->name, argv[i]);
1573 } else {
1574 ctl_fatal("'%s' option on '%s' does not accept an "
1575 "argument", node->name, argv[i]);
1576 }
1577 }
1578 }
1579
1580 n_arg = argc - i - 1;
1581 if (n_arg < p->min_args) {
1582 ctl_fatal("'%s' command requires at least %d arguments",
1583 p->name, p->min_args);
1584 } else if (n_arg > p->max_args) {
1585 int j;
1586
1587 for (j = i + 1; j < argc; j++) {
1588 if (argv[j][0] == '-') {
1589 ctl_fatal("'%s' command takes at most %d arguments "
1590 "(note that options must precede command "
1591 "names and follow a \"--\" argument)",
1592 p->name, p->max_args);
1593 }
1594 }
1595
1596 ctl_fatal("'%s' command takes at most %d arguments",
1597 p->name, p->max_args);
1598 }
1599
1600 command->syntax = p;
1601 command->argc = n_arg + 1;
1602 command->argv = &argv[i];
1603 }
1604
1605 static void
1606 pre_cmd_show(struct ctl_context *ctx)
1607 {
1608 struct cmd_show_table *show;
1609
1610 for (show = cmd_show_tables; show->table; show++) {
1611 size_t i;
1612
1613 ovsdb_idl_add_table(ctx->idl, show->table);
1614 if (show->name_column) {
1615 ovsdb_idl_add_column(ctx->idl, show->name_column);
1616 }
1617 for (i = 0; i < ARRAY_SIZE(show->columns); i++) {
1618 const struct ovsdb_idl_column *column = show->columns[i];
1619 if (column) {
1620 ovsdb_idl_add_column(ctx->idl, column);
1621 }
1622 }
1623 }
1624 }
1625
1626 static struct cmd_show_table *
1627 cmd_show_find_table_by_row(const struct ovsdb_idl_row *row)
1628 {
1629 struct cmd_show_table *show;
1630
1631 for (show = cmd_show_tables; show->table; show++) {
1632 if (show->table == row->table->class) {
1633 return show;
1634 }
1635 }
1636 return NULL;
1637 }
1638
1639 static struct cmd_show_table *
1640 cmd_show_find_table_by_name(const char *name)
1641 {
1642 struct cmd_show_table *show;
1643
1644 for (show = cmd_show_tables; show->table; show++) {
1645 if (!strcmp(show->table->name, name)) {
1646 return show;
1647 }
1648 }
1649 return NULL;
1650 }
1651
1652 /* 'shown' records the tables that has been displayed by the current
1653 * command to avoid duplicated prints.
1654 */
1655 static void
1656 cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row,
1657 int level, struct sset *shown)
1658 {
1659 struct cmd_show_table *show = cmd_show_find_table_by_row(row);
1660 size_t i;
1661
1662 ds_put_char_multiple(&ctx->output, ' ', level * 4);
1663 if (show && show->name_column) {
1664 const struct ovsdb_datum *datum;
1665
1666 ds_put_format(&ctx->output, "%s ", show->table->name);
1667 datum = ovsdb_idl_read(row, show->name_column);
1668 ovsdb_datum_to_string(datum, &show->name_column->type, &ctx->output);
1669 } else {
1670 ds_put_format(&ctx->output, UUID_FMT, UUID_ARGS(&row->uuid));
1671 }
1672 ds_put_char(&ctx->output, '\n');
1673
1674 if (!show || sset_find(shown, show->table->name)) {
1675 return;
1676 }
1677
1678 sset_add(shown, show->table->name);
1679 for (i = 0; i < ARRAY_SIZE(show->columns); i++) {
1680 const struct ovsdb_idl_column *column = show->columns[i];
1681 const struct ovsdb_datum *datum;
1682
1683 if (!column) {
1684 break;
1685 }
1686
1687 datum = ovsdb_idl_read(row, column);
1688 if (column->type.key.type == OVSDB_TYPE_UUID &&
1689 column->type.key.u.uuid.refTableName) {
1690 struct cmd_show_table *ref_show;
1691 size_t j;
1692
1693 ref_show = cmd_show_find_table_by_name(
1694 column->type.key.u.uuid.refTableName);
1695 if (ref_show) {
1696 for (j = 0; j < datum->n; j++) {
1697 const struct ovsdb_idl_row *ref_row;
1698
1699 ref_row = ovsdb_idl_get_row_for_uuid(ctx->idl,
1700 ref_show->table,
1701 &datum->keys[j].uuid);
1702 if (ref_row) {
1703 cmd_show_row(ctx, ref_row, level + 1, shown);
1704 }
1705 }
1706 continue;
1707 }
1708 } else if (ovsdb_type_is_map(&column->type) &&
1709 column->type.value.type == OVSDB_TYPE_UUID &&
1710 column->type.value.u.uuid.refTableName) {
1711 struct cmd_show_table *ref_show;
1712 size_t j;
1713
1714 /* Prints the key to ref'ed table name map if the ref'ed table
1715 * is also defined in 'cmd_show_tables'. */
1716 ref_show = cmd_show_find_table_by_name(
1717 column->type.value.u.uuid.refTableName);
1718 if (ref_show && ref_show->name_column) {
1719 ds_put_char_multiple(&ctx->output, ' ', (level + 1) * 4);
1720 ds_put_format(&ctx->output, "%s:\n", column->name);
1721 for (j = 0; j < datum->n; j++) {
1722 const struct ovsdb_idl_row *ref_row;
1723
1724 ref_row = ovsdb_idl_get_row_for_uuid(ctx->idl,
1725 ref_show->table,
1726 &datum->values[j].uuid);
1727
1728 ds_put_char_multiple(&ctx->output, ' ', (level + 2) * 4);
1729 ovsdb_atom_to_string(&datum->keys[j], column->type.key.type,
1730 &ctx->output);
1731 ds_put_char(&ctx->output, '=');
1732 if (ref_row) {
1733 const struct ovsdb_datum *ref_datum;
1734
1735 ref_datum = ovsdb_idl_read(ref_row,
1736 ref_show->name_column);
1737 ovsdb_datum_to_string(ref_datum,
1738 &ref_show->name_column->type,
1739 &ctx->output);
1740 } else {
1741 ds_put_cstr(&ctx->output, "\"<null>\"");
1742 }
1743 ds_put_char(&ctx->output, '\n');
1744 }
1745 continue;
1746 }
1747 }
1748
1749 if (!ovsdb_datum_is_default(datum, &column->type)) {
1750 ds_put_char_multiple(&ctx->output, ' ', (level + 1) * 4);
1751 ds_put_format(&ctx->output, "%s: ", column->name);
1752 ovsdb_datum_to_string(datum, &column->type, &ctx->output);
1753 ds_put_char(&ctx->output, '\n');
1754 }
1755 }
1756 sset_find_and_delete_assert(shown, show->table->name);
1757 }
1758
1759 static void
1760 cmd_show(struct ctl_context *ctx)
1761 {
1762 const struct ovsdb_idl_row *row;
1763 struct sset shown = SSET_INITIALIZER(&shown);
1764
1765 for (row = ovsdb_idl_first_row(ctx->idl, cmd_show_tables[0].table);
1766 row; row = ovsdb_idl_next_row(row)) {
1767 cmd_show_row(ctx, row, 0, &shown);
1768 }
1769
1770 ovs_assert(sset_is_empty(&shown));
1771 sset_destroy(&shown);
1772 }
1773
1774 \f
1775 /* Given pointer to dynamic array 'options_p', array's current size
1776 * 'allocated_options_p' and number of added options 'n_options_p',
1777 * adds all command options to the array. Enlarges the array if
1778 * necessary. */
1779 void
1780 ctl_add_cmd_options(struct option **options_p, size_t *n_options_p,
1781 size_t *allocated_options_p, int opt_val)
1782 {
1783 struct option *o;
1784 const struct shash_node *node;
1785 size_t n_existing_options = *n_options_p;
1786
1787 SHASH_FOR_EACH (node, &all_commands) {
1788 const struct ctl_command_syntax *p = node->data;
1789
1790 if (p->options[0]) {
1791 char *save_ptr = NULL;
1792 char *name;
1793 char *s;
1794
1795 s = xstrdup(p->options);
1796 for (name = strtok_r(s, ",", &save_ptr); name != NULL;
1797 name = strtok_r(NULL, ",", &save_ptr)) {
1798 char *equals;
1799 int has_arg;
1800
1801 ovs_assert(name[0] == '-' && name[1] == '-' && name[2]);
1802 name += 2;
1803
1804 equals = strchr(name, '=');
1805 if (equals) {
1806 has_arg = required_argument;
1807 *equals = '\0';
1808 } else {
1809 has_arg = no_argument;
1810 }
1811
1812 o = find_option(name, *options_p, *n_options_p);
1813 if (o) {
1814 ovs_assert(o - *options_p >= n_existing_options);
1815 ovs_assert(o->has_arg == has_arg);
1816 } else {
1817 o = add_option(options_p, n_options_p, allocated_options_p);
1818 o->name = xstrdup(name);
1819 o->has_arg = has_arg;
1820 o->flag = NULL;
1821 o->val = opt_val;
1822 }
1823 }
1824
1825 free(s);
1826 }
1827 }
1828 o = add_option(options_p, n_options_p, allocated_options_p);
1829 memset(o, 0, sizeof *o);
1830 }
1831
1832 /* Parses command-line input for commands. */
1833 struct ctl_command *
1834 ctl_parse_commands(int argc, char *argv[], struct shash *local_options,
1835 size_t *n_commandsp)
1836 {
1837 struct ctl_command *commands;
1838 size_t n_commands, allocated_commands;
1839 int i, start;
1840
1841 commands = NULL;
1842 n_commands = allocated_commands = 0;
1843
1844 for (start = i = 0; i <= argc; i++) {
1845 if (i == argc || !strcmp(argv[i], "--")) {
1846 if (i > start) {
1847 if (n_commands >= allocated_commands) {
1848 struct ctl_command *c;
1849
1850 commands = x2nrealloc(commands, &allocated_commands,
1851 sizeof *commands);
1852 for (c = commands; c < &commands[n_commands]; c++) {
1853 shash_moved(&c->options);
1854 }
1855 }
1856 parse_command(i - start, &argv[start], local_options,
1857 &commands[n_commands++]);
1858 } else if (!shash_is_empty(local_options)) {
1859 ctl_fatal("missing command name (use --help for help)");
1860 }
1861 start = i + 1;
1862 }
1863 }
1864 if (!n_commands) {
1865 ctl_fatal("missing command name (use --help for help)");
1866 }
1867 *n_commandsp = n_commands;
1868 return commands;
1869 }
1870
1871 /* Prints all registered commands. */
1872 void
1873 ctl_print_commands(void)
1874 {
1875 const struct shash_node *node;
1876
1877 SHASH_FOR_EACH (node, &all_commands) {
1878 const struct ctl_command_syntax *p = node->data;
1879 char *options = xstrdup(p->options);
1880 char *options_begin = options;
1881 char *item;
1882
1883 for (item = strsep(&options, ","); item != NULL;
1884 item = strsep(&options, ",")) {
1885 if (item[0] != '\0') {
1886 printf("[%s] ", item);
1887 }
1888 }
1889 printf(",%s,", p->name);
1890 print_command_arguments(p);
1891 printf("\n");
1892
1893 free(options_begin);
1894 }
1895
1896 exit(EXIT_SUCCESS);
1897 }
1898
1899 /* Given array of options 'options', prints them. */
1900 void
1901 ctl_print_options(const struct option *options)
1902 {
1903 for (; options->name; options++) {
1904 const struct option *o = options;
1905
1906 printf("--%s%s\n", o->name, o->has_arg ? "=ARG" : "");
1907 if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) {
1908 printf("-%c%s\n", o->val, o->has_arg ? " ARG" : "");
1909 }
1910 }
1911
1912 exit(EXIT_SUCCESS);
1913 }
1914
1915 /* Returns the default local database path. */
1916 char *
1917 ctl_default_db(void)
1918 {
1919 static char *def;
1920 if (!def) {
1921 def = xasprintf("unix:%s/db.sock", ovs_rundir());
1922 }
1923 return def;
1924 }
1925
1926 /* Returns true if it looks like this set of arguments might modify the
1927 * database, otherwise false. (Not very smart, so it's prone to false
1928 * positives.) */
1929 bool
1930 ctl_might_write_to_db(char **argv)
1931 {
1932 for (; *argv; argv++) {
1933 const struct ctl_command_syntax *p = shash_find_data(&all_commands,
1934 *argv);
1935 if (p && p->mode == RW) {
1936 return true;
1937 }
1938 }
1939 return false;
1940 }
1941
1942 void
1943 ctl_fatal(const char *format, ...)
1944 {
1945 char *message;
1946 va_list args;
1947
1948 va_start(args, format);
1949 message = xvasprintf(format, args);
1950 va_end(args);
1951
1952 vlog_set_levels(&VLM_db_ctl_base, VLF_CONSOLE, VLL_OFF);
1953 VLOG_ERR("%s", message);
1954 ovs_error(0, "%s", message);
1955 ctl_exit(EXIT_FAILURE);
1956 }
1957
1958 /* Frees the current transaction and the underlying IDL and then calls
1959 * exit(status).
1960 *
1961 * Freeing the transaction and the IDL is not strictly necessary, but it makes
1962 * for a clean memory leak report from valgrind in the normal case. That makes
1963 * it easier to notice real memory leaks. */
1964 static void
1965 ctl_exit(int status)
1966 {
1967 if (ctl_exit_func) {
1968 ctl_exit_func(status);
1969 }
1970 exit(status);
1971 }
1972
1973 /* Comman database commands to be registered. */
1974 static const struct ctl_command_syntax db_ctl_commands[] = {
1975 {"comment", 0, INT_MAX, "[ARG]...", NULL, NULL, NULL, "", RO},
1976 {"get", 2, INT_MAX, "TABLE RECORD [COLUMN[:KEY]]...",pre_cmd_get, cmd_get,
1977 NULL, "--if-exists,--id=", RO},
1978 {"list", 1, INT_MAX, "TABLE [RECORD]...", pre_cmd_list, cmd_list, NULL,
1979 "--if-exists,--columns=", RO},
1980 {"find", 1, INT_MAX, "TABLE [COLUMN[:KEY]=VALUE]...", pre_cmd_find,
1981 cmd_find, NULL, "--columns=", RO},
1982 {"set", 3, INT_MAX, "TABLE RECORD COLUMN[:KEY]=VALUE...", pre_cmd_set,
1983 cmd_set, NULL, "--if-exists", RW},
1984 {"add", 4, INT_MAX, "TABLE RECORD COLUMN [KEY=]VALUE...", pre_cmd_add,
1985 cmd_add, NULL, "--if-exists", RW},
1986 {"remove", 4, INT_MAX, "TABLE RECORD COLUMN KEY|VALUE|KEY=VALUE...",
1987 pre_cmd_remove, cmd_remove, NULL, "--if-exists", RW},
1988 {"clear", 3, INT_MAX, "TABLE RECORD COLUMN...", pre_cmd_clear, cmd_clear,
1989 NULL, "--if-exists", RW},
1990 {"create", 2, INT_MAX, "TABLE COLUMN[:KEY]=VALUE...", pre_create,
1991 cmd_create, post_create, "--id=", RW},
1992 {"destroy", 1, INT_MAX, "TABLE [RECORD]...", pre_cmd_destroy, cmd_destroy,
1993 NULL, "--if-exists,--all", RW},
1994 {"wait-until", 2, INT_MAX, "TABLE RECORD [COLUMN[:KEY]=VALUE]...",
1995 pre_cmd_wait_until, cmd_wait_until, NULL, "", RO},
1996 {"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO},
1997 {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
1998 };
1999
2000 /* Registers commands represented by 'struct ctl_command_syntax's to
2001 * 'all_commands'. The last element of 'commands' must be an all-NULL
2002 * element. */
2003 void
2004 ctl_register_commands(const struct ctl_command_syntax *commands)
2005 {
2006 const struct ctl_command_syntax *p;
2007
2008 for (p = commands; p->name; p++) {
2009 shash_add_assert(&all_commands, p->name, p);
2010 }
2011 }
2012
2013 /* Registers the 'db_ctl_commands' to 'all_commands'. */
2014 void
2015 ctl_init(const struct ctl_table_class tables_[],
2016 void (*ctl_exit_func_)(int status))
2017 {
2018 tables = tables_;
2019 ctl_exit_func = ctl_exit_func_;
2020 ctl_register_commands(db_ctl_commands);
2021 }
2022
2023 /* Returns the text for the database commands usage. */
2024 const char *
2025 ctl_get_db_cmd_usage(void)
2026 {
2027 return "Database commands:\n\
2028 list TBL [REC] list RECord (or all records) in TBL\n\
2029 find TBL CONDITION... list records satisfying CONDITION in TBL\n\
2030 get TBL REC COL[:KEY] print values of COLumns in RECord in TBL\n\
2031 set TBL REC COL[:KEY]=VALUE set COLumn values in RECord in TBL\n\
2032 add TBL REC COL [KEY=]VALUE add (KEY=)VALUE to COLumn in RECord in TBL\n\
2033 remove TBL REC COL [KEY=]VALUE remove (KEY=)VALUE from COLumn\n\
2034 clear TBL REC COL clear values from COLumn in RECord in TBL\n\
2035 create TBL COL[:KEY]=VALUE create and initialize new record\n\
2036 destroy TBL REC delete RECord from TBL\n\
2037 wait-until TBL REC [COL[:KEY]=VALUE] wait until condition is true\n\
2038 Potentially unsafe database commands require --force option.\n";
2039 }
2040
2041 /* Initializes 'ctx' from 'command'. */
2042 void
2043 ctl_context_init_command(struct ctl_context *ctx,
2044 struct ctl_command *command)
2045 {
2046 ctx->argc = command->argc;
2047 ctx->argv = command->argv;
2048 ctx->options = command->options;
2049
2050 ds_swap(&ctx->output, &command->output);
2051 ctx->table = command->table;
2052 ctx->try_again = false;
2053 }
2054
2055 /* Initializes the entire 'ctx'. */
2056 void
2057 ctl_context_init(struct ctl_context *ctx, struct ctl_command *command,
2058 struct ovsdb_idl *idl, struct ovsdb_idl_txn *txn,
2059 struct ovsdb_symbol_table *symtab,
2060 void (*invalidate_cache)(struct ctl_context *))
2061 {
2062 if (command) {
2063 ctl_context_init_command(ctx, command);
2064 }
2065 ctx->idl = idl;
2066 ctx->txn = txn;
2067 ctx->symtab = symtab;
2068 ctx->invalidate_cache = invalidate_cache;
2069 }
2070
2071 /* Completes processing of 'command' within 'ctx'. */
2072 void
2073 ctl_context_done_command(struct ctl_context *ctx,
2074 struct ctl_command *command)
2075 {
2076 ds_swap(&ctx->output, &command->output);
2077 command->table = ctx->table;
2078 }
2079
2080 /* Finishes up with 'ctx'.
2081 *
2082 * If command is nonnull, first calls ctl_context_done_command() to complete
2083 * processing that command within 'ctx'. */
2084 void
2085 ctl_context_done(struct ctl_context *ctx,
2086 struct ctl_command *command)
2087 {
2088 if (command) {
2089 ctl_context_done_command(ctx, command);
2090 }
2091 invalidate_cache(ctx);
2092 }
2093
2094 void ctl_set_column(const char *table_name,
2095 const struct ovsdb_idl_row *row, const char *arg,
2096 struct ovsdb_symbol_table *symtab)
2097 {
2098 set_column(get_table(table_name), row, arg, symtab);
2099 }