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