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