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