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