LCOV - code coverage report
Current view: top level - lib - db-ctl-base.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 921 968 95.1 %
Date: 2016-09-14 01:02:56 Functions: 71 72 98.6 %
Branches: 492 578 85.1 %

           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 = &equals;
     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 : }

Generated by: LCOV version 1.12