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