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