LCOV - code coverage report
Current view: top level - ovsdb - ovsdb-client.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 612 750 81.6 %
Date: 2016-09-14 01:02:56 Functions: 47 54 87.0 %
Branches: 254 375 67.7 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 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 <errno.h>
      21                 :            : #include <getopt.h>
      22                 :            : #include <limits.h>
      23                 :            : #include <signal.h>
      24                 :            : #include <stdlib.h>
      25                 :            : #include <string.h>
      26                 :            : #include <unistd.h>
      27                 :            : 
      28                 :            : #include "command-line.h"
      29                 :            : #include "column.h"
      30                 :            : #include "compiler.h"
      31                 :            : #include "daemon.h"
      32                 :            : #include "dirs.h"
      33                 :            : #include "openvswitch/dynamic-string.h"
      34                 :            : #include "fatal-signal.h"
      35                 :            : #include "openvswitch/json.h"
      36                 :            : #include "jsonrpc.h"
      37                 :            : #include "lib/table.h"
      38                 :            : #include "ovsdb.h"
      39                 :            : #include "ovsdb-data.h"
      40                 :            : #include "ovsdb-error.h"
      41                 :            : #include "poll-loop.h"
      42                 :            : #include "sort.h"
      43                 :            : #include "svec.h"
      44                 :            : #include "stream.h"
      45                 :            : #include "stream-ssl.h"
      46                 :            : #include "table.h"
      47                 :            : #include "monitor.h"
      48                 :            : #include "condition.h"
      49                 :            : #include "timeval.h"
      50                 :            : #include "unixctl.h"
      51                 :            : #include "util.h"
      52                 :            : #include "openvswitch/vlog.h"
      53                 :            : 
      54                 :       1812 : VLOG_DEFINE_THIS_MODULE(ovsdb_client);
      55                 :            : 
      56                 :            : enum args_needed {
      57                 :            :     NEED_NONE,            /* No JSON-RPC connection or database name needed. */
      58                 :            :     NEED_RPC,             /* JSON-RPC connection needed. */
      59                 :            :     NEED_DATABASE         /* JSON-RPC connection and database name needed. */
      60                 :            : };
      61                 :            : 
      62                 :            : struct ovsdb_client_command {
      63                 :            :     const char *name;
      64                 :            :     enum args_needed need;
      65                 :            :     int min_args;
      66                 :            :     int max_args;
      67                 :            :     void (*handler)(struct jsonrpc *rpc, const char *database,
      68                 :            :                     int argc, char *argv[]);
      69                 :            : };
      70                 :            : 
      71                 :            : /* --timestamp: Print a timestamp before each update on "monitor" command? */
      72                 :            : static bool timestamp;
      73                 :            : 
      74                 :            : /* Format for table output. */
      75                 :            : static struct table_style table_style = TABLE_STYLE_DEFAULT;
      76                 :            : 
      77                 :            : static const struct ovsdb_client_command *get_all_commands(void);
      78                 :            : 
      79                 :            : OVS_NO_RETURN static void usage(void);
      80                 :            : static void parse_options(int argc, char *argv[]);
      81                 :            : static struct jsonrpc *open_jsonrpc(const char *server);
      82                 :            : static void fetch_dbs(struct jsonrpc *, struct svec *dbs);
      83                 :            : 
      84                 :            : int
      85                 :        906 : main(int argc, char *argv[])
      86                 :            : {
      87                 :            :     const struct ovsdb_client_command *command;
      88                 :            :     char *database;
      89                 :            :     struct jsonrpc *rpc;
      90                 :            : 
      91                 :        906 :     ovs_cmdl_proctitle_init(argc, argv);
      92                 :        906 :     set_program_name(argv[0]);
      93                 :        906 :     parse_options(argc, argv);
      94                 :        906 :     fatal_ignore_sigpipe();
      95                 :            : 
      96                 :        906 :     daemon_become_new_user(false);
      97         [ -  + ]:        906 :     if (optind >= argc) {
      98                 :          0 :         ovs_fatal(0, "missing command name; use --help for help");
      99                 :            :     }
     100                 :            : 
     101                 :        906 :     for (command = get_all_commands(); ; command++) {
     102         [ -  + ]:       5681 :         if (!command->name) {
     103                 :          0 :             VLOG_FATAL("unknown command '%s'; use --help for help",
     104                 :            :                        argv[optind]);
     105         [ +  + ]:       5681 :         } else if (!strcmp(command->name, argv[optind])) {
     106                 :        906 :             break;
     107                 :            :         }
     108                 :       4775 :     }
     109                 :        906 :     optind++;
     110                 :            : 
     111         [ +  - ]:        906 :     if (command->need != NEED_NONE) {
     112         [ +  + ]:        906 :         if (argc - optind > command->min_args
     113         [ +  - ]:        748 :             && (isalpha((unsigned char) argv[optind][0])
     114         [ +  + ]:        748 :                 && strchr(argv[optind], ':'))) {
     115                 :        706 :             rpc = open_jsonrpc(argv[optind++]);
     116                 :            :         } else {
     117                 :        200 :             char *sock = xasprintf("unix:%s/db.sock", ovs_rundir());
     118                 :        200 :             rpc = open_jsonrpc(sock);
     119                 :        906 :             free(sock);
     120                 :            :         }
     121                 :            :     } else {
     122                 :          0 :         rpc = NULL;
     123                 :            :     }
     124                 :            : 
     125         [ +  + ]:        906 :     if (command->need == NEED_DATABASE) {
     126                 :            :         struct svec dbs;
     127                 :            : 
     128                 :        167 :         svec_init(&dbs);
     129                 :        167 :         fetch_dbs(rpc, &dbs);
     130         [ +  + ]:        167 :         if (argc - optind > command->min_args
     131         [ +  + ]:         79 :             && svec_contains(&dbs, argv[optind])) {
     132                 :         77 :             database = xstrdup(argv[optind++]);
     133         [ +  + ]:         90 :         } else if (dbs.n == 1) {
     134                 :         89 :             database = xstrdup(dbs.names[0]);
     135         [ -  + ]:          1 :         } else if (svec_contains(&dbs, "Open_vSwitch")) {
     136                 :          0 :             database = xstrdup("Open_vSwitch");
     137                 :            :         } else {
     138                 :          1 :             jsonrpc_close(rpc);
     139                 :          1 :             ovs_fatal(0, "no default database for `%s' command, please "
     140                 :            :                       "specify a database name", command->name);
     141                 :            :         }
     142                 :        166 :         svec_destroy(&dbs);
     143                 :            :     } else {
     144                 :        739 :         database = NULL;
     145                 :            :     }
     146                 :            : 
     147 [ +  - ][ +  + ]:        905 :     if (argc - optind < command->min_args ||
     148                 :        905 :         argc - optind > command->max_args) {
     149                 :          1 :         free(database);
     150                 :          1 :         VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
     151                 :            :                     command->name);
     152                 :            :     }
     153                 :            : 
     154                 :        904 :     command->handler(rpc, database, argc - optind, argv + optind);
     155                 :            : 
     156                 :        876 :     free(database);
     157                 :        876 :     jsonrpc_close(rpc);
     158                 :            : 
     159         [ -  + ]:        876 :     if (ferror(stdout)) {
     160                 :          0 :         VLOG_FATAL("write to stdout failed");
     161                 :            :     }
     162         [ -  + ]:        876 :     if (ferror(stderr)) {
     163                 :          0 :         VLOG_FATAL("write to stderr failed");
     164                 :            :     }
     165                 :            : 
     166                 :        876 :     return 0;
     167                 :            : }
     168                 :            : 
     169                 :            : static void
     170                 :        906 : parse_options(int argc, char *argv[])
     171                 :            : {
     172                 :            :     enum {
     173                 :            :         OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
     174                 :            :         OPT_TIMESTAMP,
     175                 :            :         VLOG_OPTION_ENUMS,
     176                 :            :         DAEMON_OPTION_ENUMS,
     177                 :            :         TABLE_OPTION_ENUMS
     178                 :            :     };
     179                 :            :     static const struct option long_options[] = {
     180                 :            :         {"help", no_argument, NULL, 'h'},
     181                 :            :         {"version", no_argument, NULL, 'V'},
     182                 :            :         {"timestamp", no_argument, NULL, OPT_TIMESTAMP},
     183                 :            :         VLOG_LONG_OPTIONS,
     184                 :            :         DAEMON_LONG_OPTIONS,
     185                 :            : #ifdef HAVE_OPENSSL
     186                 :            :         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
     187                 :            :         STREAM_SSL_LONG_OPTIONS,
     188                 :            : #endif
     189                 :            :         TABLE_LONG_OPTIONS,
     190                 :            :         {NULL, 0, NULL, 0},
     191                 :            :     };
     192                 :        906 :     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
     193                 :            : 
     194                 :            :     for (;;) {
     195                 :            :         int c;
     196                 :            : 
     197                 :       1413 :         c = getopt_long(argc, argv, short_options, long_options, NULL);
     198         [ +  + ]:       1413 :         if (c == -1) {
     199                 :        906 :             break;
     200                 :            :         }
     201                 :            : 
     202   [ -  -  +  +  :        507 :         switch (c) {
          -  -  +  -  +  
          +  -  -  -  +  
          +  +  -  -  +  
          +  +  -  -  -  
                   -  - ]
     203                 :            :         case 'h':
     204                 :          0 :             usage();
     205                 :            : 
     206                 :            :         case 'V':
     207                 :          0 :             ovs_print_version(0, 0);
     208                 :          0 :             exit(EXIT_SUCCESS);
     209                 :            : 
     210                 :         35 :         VLOG_OPTION_HANDLERS
     211                 :         77 :         DAEMON_OPTION_HANDLERS
     212                 :         86 :         TABLE_OPTION_HANDLERS(&table_style)
     213                 :        309 :         STREAM_SSL_OPTION_HANDLERS
     214                 :            : 
     215                 :            :         case OPT_BOOTSTRAP_CA_CERT:
     216                 :          0 :             stream_ssl_set_ca_cert_file(optarg, true);
     217                 :          0 :             break;
     218                 :            : 
     219                 :            :         case OPT_TIMESTAMP:
     220                 :          0 :             timestamp = true;
     221                 :          0 :             break;
     222                 :            : 
     223                 :            :         case '?':
     224                 :          0 :             exit(EXIT_FAILURE);
     225                 :            : 
     226                 :            :         case 0:
     227                 :            :             /* getopt_long() already set the value for us. */
     228                 :          0 :             break;
     229                 :            : 
     230                 :            :         default:
     231                 :          0 :             abort();
     232                 :            :         }
     233                 :        507 :     }
     234                 :        906 :     free(short_options);
     235                 :        906 : }
     236                 :            : 
     237                 :            : static void
     238                 :          0 : usage(void)
     239                 :            : {
     240                 :          0 :     printf("%s: Open vSwitch database JSON-RPC client\n"
     241                 :            :            "usage: %s [OPTIONS] COMMAND [ARG...]\n"
     242                 :            :            "\nValid commands are:\n"
     243                 :            :            "\n  list-dbs [SERVER]\n"
     244                 :            :            "    list databases available on SERVER\n"
     245                 :            :            "\n  get-schema [SERVER] [DATABASE]\n"
     246                 :            :            "    retrieve schema for DATABASE from SERVER\n"
     247                 :            :            "\n  get-schema-version [SERVER] [DATABASE]\n"
     248                 :            :            "    retrieve schema for DATABASE from SERVER and report only its\n"
     249                 :            :            "    version number on stdout\n"
     250                 :            :            "\n  list-tables [SERVER] [DATABASE]\n"
     251                 :            :            "    list tables for DATABASE on SERVER\n"
     252                 :            :            "\n  list-columns [SERVER] [DATABASE] [TABLE]\n"
     253                 :            :            "    list columns in TABLE (or all tables) in DATABASE on SERVER\n"
     254                 :            :            "\n  transact [SERVER] TRANSACTION\n"
     255                 :            :            "    run TRANSACTION (a JSON array of operations) on SERVER\n"
     256                 :            :            "    and print the results as JSON on stdout\n"
     257                 :            :            "\n  monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
     258                 :            :            "    monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
     259                 :            :            "    COLUMNs may include !initial, !insert, !delete, !modify\n"
     260                 :            :            "    to avoid seeing the specified kinds of changes.\n"
     261                 :            :            "\n  monitor-cond [SERVER] [DATABASE] CONDITION TABLE [COLUMN,...]...\n"
     262                 :            :            "    monitor contents that match CONDITION of COLUMNs in TABLE in\n"
     263                 :            :            "    DATABASE on SERVER.\n"
     264                 :            :            "    COLUMNs may include !initial, !insert, !delete, !modify\n"
     265                 :            :            "    to avoid seeing the specified kinds of changes.\n"
     266                 :            :            "\n  monitor [SERVER] [DATABASE] ALL\n"
     267                 :            :            "    monitor all changes to all columns in all tables\n"
     268                 :            :            "    in DATBASE on SERVER.\n"
     269                 :            :            "\n  dump [SERVER] [DATABASE]\n"
     270                 :            :            "    dump contents of DATABASE on SERVER to stdout\n"
     271                 :            :            "\n  lock [SERVER] LOCK\n"
     272                 :            :            "    create or wait for LOCK in SERVER\n"
     273                 :            :            "\n  steal [SERVER] LOCK\n"
     274                 :            :            "    steal LOCK from SERVER\n"
     275                 :            :            "\n  unlock [SERVER] LOCK\n"
     276                 :            :            "    unlock LOCK from SERVER\n"
     277                 :            :            "\nThe default SERVER is unix:%s/db.sock.\n"
     278                 :            :            "The default DATABASE is Open_vSwitch.\n",
     279                 :            :            program_name, program_name, ovs_rundir());
     280                 :          0 :     stream_usage("SERVER", true, true, true);
     281                 :          0 :     printf("\nOutput formatting options:\n"
     282                 :            :            "  -f, --format=FORMAT         set output formatting to FORMAT\n"
     283                 :            :            "                              (\"table\", \"html\", \"csv\", "
     284                 :            :            "or \"json\")\n"
     285                 :            :            "  --no-headings               omit table heading row\n"
     286                 :            :            "  --pretty                    pretty-print JSON in output\n"
     287                 :            :            "  --timestamp                 timestamp \"monitor\" output");
     288                 :          0 :     daemon_usage();
     289                 :          0 :     vlog_usage();
     290                 :          0 :     printf("\nOther options:\n"
     291                 :            :            "  -h, --help                  display this help message\n"
     292                 :            :            "  -V, --version               display version information\n");
     293                 :          0 :     exit(EXIT_SUCCESS);
     294                 :            : }
     295                 :            : 
     296                 :            : static void
     297                 :       1164 : check_txn(int error, struct jsonrpc_msg **reply_)
     298                 :            : {
     299                 :       1164 :     struct jsonrpc_msg *reply = *reply_;
     300                 :            : 
     301         [ -  + ]:       1164 :     if (error) {
     302                 :          0 :         ovs_fatal(error, "transaction failed");
     303                 :            :     }
     304                 :            : 
     305         [ -  + ]:       1164 :     if (reply->error) {
     306                 :          0 :         ovs_fatal(error, "transaction returned error: %s",
     307                 :          0 :                   json_to_string(reply->error, table_style.json_flags));
     308                 :            :     }
     309                 :       1164 : }
     310                 :            : 
     311                 :            : static struct json *
     312                 :        739 : parse_json(const char *s)
     313                 :            : {
     314                 :        739 :     struct json *json = json_from_string(s);
     315         [ -  + ]:        739 :     if (json->type == JSON_STRING) {
     316                 :          0 :         ovs_fatal(0, "\"%s\": %s", s, json->u.string);
     317                 :            :     }
     318                 :        739 :     return json;
     319                 :            : }
     320                 :            : 
     321                 :            : static struct jsonrpc *
     322                 :        906 : open_jsonrpc(const char *server)
     323                 :            : {
     324                 :            :     struct stream *stream;
     325                 :            :     int error;
     326                 :            : 
     327                 :        906 :     error = stream_open_block(jsonrpc_stream_open(server, &stream,
     328                 :            :                               DSCP_DEFAULT), &stream);
     329         [ -  + ]:        906 :     if (error == EAFNOSUPPORT) {
     330                 :            :         struct pstream *pstream;
     331                 :            : 
     332                 :          0 :         error = jsonrpc_pstream_open(server, &pstream, DSCP_DEFAULT);
     333         [ #  # ]:          0 :         if (error) {
     334                 :          0 :             ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
     335                 :            :         }
     336                 :            : 
     337         [ #  # ]:          0 :         VLOG_INFO("%s: waiting for connection...", server);
     338                 :          0 :         error = pstream_accept_block(pstream, &stream);
     339         [ #  # ]:          0 :         if (error) {
     340                 :          0 :             ovs_fatal(error, "failed to accept connection on \"%s\"", server);
     341                 :            :         }
     342                 :            : 
     343                 :          0 :         pstream_close(pstream);
     344         [ -  + ]:        906 :     } else if (error) {
     345                 :          0 :         ovs_fatal(error, "failed to connect to \"%s\"", server);
     346                 :            :     }
     347                 :            : 
     348                 :        906 :     return jsonrpc_open(stream);
     349                 :            : }
     350                 :            : 
     351                 :            : static void
     352                 :        743 : print_json(struct json *json)
     353                 :            : {
     354                 :        743 :     char *string = json_to_string(json, table_style.json_flags);
     355                 :        743 :     fputs(string, stdout);
     356                 :        743 :     free(string);
     357                 :        743 : }
     358                 :            : 
     359                 :            : static void
     360                 :          0 : print_and_free_json(struct json *json)
     361                 :            : {
     362                 :          0 :     print_json(json);
     363                 :          0 :     json_destroy(json);
     364                 :          0 : }
     365                 :            : 
     366                 :            : static void
     367                 :        645 : check_ovsdb_error(struct ovsdb_error *error)
     368                 :            : {
     369         [ -  + ]:        645 :     if (error) {
     370                 :          0 :         ovs_fatal(0, "%s", ovsdb_error_to_string(error));
     371                 :            :     }
     372                 :        645 : }
     373                 :            : 
     374                 :            : static struct ovsdb_schema *
     375                 :        171 : fetch_schema(struct jsonrpc *rpc, const char *database)
     376                 :            : {
     377                 :            :     struct jsonrpc_msg *request, *reply;
     378                 :            :     struct ovsdb_schema *schema;
     379                 :            : 
     380                 :        171 :     request = jsonrpc_create_request("get_schema",
     381                 :            :                                      json_array_create_1(
     382                 :            :                                          json_string_create(database)),
     383                 :            :                                      NULL);
     384                 :        171 :     check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
     385                 :        171 :     check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
     386                 :        171 :     jsonrpc_msg_destroy(reply);
     387                 :            : 
     388                 :        171 :     return schema;
     389                 :            : }
     390                 :            : 
     391                 :            : static void
     392                 :        168 : fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
     393                 :            : {
     394                 :            :     struct jsonrpc_msg *request, *reply;
     395                 :            :     size_t i;
     396                 :            : 
     397                 :        168 :     request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
     398                 :            :                                      NULL);
     399                 :            : 
     400                 :        168 :     check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
     401         [ -  + ]:        168 :     if (reply->result->type != JSON_ARRAY) {
     402                 :          0 :         ovs_fatal(0, "list_dbs response is not array");
     403                 :            :     }
     404                 :            : 
     405         [ +  + ]:        338 :     for (i = 0; i < reply->result->u.array.n; i++) {
     406                 :        170 :         const struct json *name = reply->result->u.array.elems[i];
     407                 :            : 
     408         [ -  + ]:        170 :         if (name->type != JSON_STRING) {
     409                 :          0 :             ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i);
     410                 :            :         }
     411                 :        170 :         svec_add(dbs, name->u.string);
     412                 :            :     }
     413                 :        168 :     jsonrpc_msg_destroy(reply);
     414                 :        168 :     svec_sort(dbs);
     415                 :        168 : }
     416                 :            : 
     417                 :            : static void
     418                 :          1 : do_list_dbs(struct jsonrpc *rpc, const char *database OVS_UNUSED,
     419                 :            :             int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     420                 :            : {
     421                 :            :     const char *db_name;
     422                 :            :     struct svec dbs;
     423                 :            :     size_t i;
     424                 :            : 
     425                 :          1 :     svec_init(&dbs);
     426                 :          1 :     fetch_dbs(rpc, &dbs);
     427 [ +  + ][ +  + ]:          3 :     SVEC_FOR_EACH (i, db_name, &dbs) {
     428                 :          2 :         puts(db_name);
     429                 :            :     }
     430                 :          1 :     svec_destroy(&dbs);
     431                 :          1 : }
     432                 :            : 
     433                 :            : static void
     434                 :          0 : do_get_schema(struct jsonrpc *rpc, const char *database,
     435                 :            :               int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     436                 :            : {
     437                 :          0 :     struct ovsdb_schema *schema = fetch_schema(rpc, database);
     438                 :          0 :     print_and_free_json(ovsdb_schema_to_json(schema));
     439                 :          0 :     ovsdb_schema_destroy(schema);
     440                 :          0 : }
     441                 :            : 
     442                 :            : static void
     443                 :          2 : do_get_schema_version(struct jsonrpc *rpc, const char *database,
     444                 :            :                       int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     445                 :            : {
     446                 :          2 :     struct ovsdb_schema *schema = fetch_schema(rpc, database);
     447                 :          2 :     puts(schema->version);
     448                 :          2 :     ovsdb_schema_destroy(schema);
     449                 :          2 : }
     450                 :            : 
     451                 :            : static void
     452                 :         27 : do_list_tables(struct jsonrpc *rpc, const char *database,
     453                 :            :                int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     454                 :            : {
     455                 :            :     struct ovsdb_schema *schema;
     456                 :            :     struct shash_node *node;
     457                 :            :     struct table t;
     458                 :            : 
     459                 :         27 :     schema = fetch_schema(rpc, database);
     460                 :         27 :     table_init(&t);
     461                 :         27 :     table_add_column(&t, "Table");
     462 [ +  + ][ -  + ]:        418 :     SHASH_FOR_EACH (node, &schema->tables) {
     463                 :        391 :         struct ovsdb_table_schema *ts = node->data;
     464                 :            : 
     465                 :        391 :         table_add_row(&t);
     466                 :        391 :         table_add_cell(&t)->text = xstrdup(ts->name);
     467                 :            :     }
     468                 :         27 :     ovsdb_schema_destroy(schema);
     469                 :         27 :     table_print(&t, &table_style);
     470                 :         27 :     table_destroy(&t);
     471                 :         27 : }
     472                 :            : 
     473                 :            : static void
     474                 :         20 : do_list_columns(struct jsonrpc *rpc, const char *database,
     475                 :            :                 int argc OVS_UNUSED, char *argv[])
     476                 :            : {
     477                 :         20 :     const char *table_name = argv[0];
     478                 :            :     struct ovsdb_schema *schema;
     479                 :            :     struct shash_node *table_node;
     480                 :            :     struct table t;
     481                 :            : 
     482                 :         20 :     schema = fetch_schema(rpc, database);
     483                 :         20 :     table_init(&t);
     484         [ -  + ]:         20 :     if (!table_name) {
     485                 :          0 :         table_add_column(&t, "Table");
     486                 :            :     }
     487                 :         20 :     table_add_column(&t, "Column");
     488                 :         20 :     table_add_column(&t, "Type");
     489 [ +  + ][ -  + ]:        340 :     SHASH_FOR_EACH (table_node, &schema->tables) {
     490                 :        320 :         struct ovsdb_table_schema *ts = table_node->data;
     491                 :            : 
     492 [ +  - ][ +  + ]:        320 :         if (!table_name || !strcmp(table_name, ts->name)) {
     493                 :            :             struct shash_node *column_node;
     494                 :            : 
     495 [ +  + ][ -  + ]:        476 :             SHASH_FOR_EACH (column_node, &ts->columns) {
     496                 :        456 :                 const struct ovsdb_column *column = column_node->data;
     497                 :            : 
     498                 :        456 :                 table_add_row(&t);
     499         [ -  + ]:        456 :                 if (!table_name) {
     500                 :          0 :                     table_add_cell(&t)->text = xstrdup(ts->name);
     501                 :            :                 }
     502                 :        456 :                 table_add_cell(&t)->text = xstrdup(column->name);
     503                 :        456 :                 table_add_cell(&t)->json = ovsdb_type_to_json(&column->type);
     504                 :            :             }
     505                 :            :         }
     506                 :            :     }
     507                 :         20 :     ovsdb_schema_destroy(schema);
     508                 :         20 :     table_print(&t, &table_style);
     509                 :         20 :     table_destroy(&t);
     510                 :         20 : }
     511                 :            : 
     512                 :            : static void
     513                 :        732 : do_transact(struct jsonrpc *rpc, const char *database OVS_UNUSED,
     514                 :            :             int argc OVS_UNUSED, char *argv[])
     515                 :            : {
     516                 :            :     struct jsonrpc_msg *request, *reply;
     517                 :            :     struct json *transaction;
     518                 :            : 
     519                 :        732 :     transaction = parse_json(argv[0]);
     520                 :            : 
     521                 :        732 :     request = jsonrpc_create_request("transact", transaction, NULL);
     522                 :        732 :     check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
     523                 :        732 :     print_json(reply->result);
     524                 :        732 :     putchar('\n');
     525                 :        732 :     jsonrpc_msg_destroy(reply);
     526                 :        732 : }
     527                 :            : 
     528                 :            : /* "monitor" command. */
     529                 :            : 
     530                 :            : struct monitored_table {
     531                 :            :     struct ovsdb_table_schema *table;
     532                 :            :     struct ovsdb_column_set columns;
     533                 :            : };
     534                 :            : 
     535                 :            : static void
     536                 :        465 : monitor_print_row(struct json *row, const char *type, const char *uuid,
     537                 :            :                   const struct ovsdb_column_set *columns, struct table *t)
     538                 :            : {
     539                 :            :     size_t i;
     540                 :            : 
     541         [ -  + ]:        465 :     if (!row) {
     542                 :          0 :         ovs_error(0, "missing %s row", type);
     543                 :          0 :         return;
     544         [ -  + ]:        465 :     } else if (row->type != JSON_OBJECT) {
     545                 :          0 :         ovs_error(0, "<row> is not object");
     546                 :          0 :         return;
     547                 :            :     }
     548                 :            : 
     549                 :        465 :     table_add_row(t);
     550                 :        465 :     table_add_cell(t)->text = xstrdup(uuid);
     551                 :        465 :     table_add_cell(t)->text = xstrdup(type);
     552         [ +  + ]:      11912 :     for (i = 0; i < columns->n_columns; i++) {
     553                 :      11447 :         const struct ovsdb_column *column = columns->columns[i];
     554                 :      11447 :         struct json *value = shash_find_data(json_object(row), column->name);
     555                 :      11447 :         struct cell *cell = table_add_cell(t);
     556         [ +  + ]:      11447 :         if (value) {
     557                 :      11386 :             cell->json = json_clone(value);
     558                 :      11386 :             cell->type = &column->type;
     559                 :            :         }
     560                 :            :     }
     561                 :            : }
     562                 :            : 
     563                 :            : static void
     564                 :         36 : monitor_print_table(struct json *table_update,
     565                 :            :                     const struct monitored_table *mt, char *caption,
     566                 :            :                     bool initial)
     567                 :            : {
     568                 :         36 :     const struct ovsdb_table_schema *table = mt->table;
     569                 :         36 :     const struct ovsdb_column_set *columns = &mt->columns;
     570                 :            :     struct shash_node *node;
     571                 :            :     struct table t;
     572                 :            :     size_t i;
     573                 :            : 
     574         [ -  + ]:         36 :     if (table_update->type != JSON_OBJECT) {
     575                 :          0 :         ovs_error(0, "<table-update> for table %s is not object", table->name);
     576                 :          0 :         return;
     577                 :            :     }
     578                 :            : 
     579                 :         36 :     table_init(&t);
     580                 :         36 :     table_set_timestamp(&t, timestamp);
     581                 :         36 :     table_set_caption(&t, caption);
     582                 :            : 
     583                 :         36 :     table_add_column(&t, "row");
     584                 :         36 :     table_add_column(&t, "action");
     585         [ +  + ]:        346 :     for (i = 0; i < columns->n_columns; i++) {
     586                 :        310 :         table_add_column(&t, "%s", columns->columns[i]->name);
     587                 :            :     }
     588 [ +  + ][ -  + ]:        476 :     SHASH_FOR_EACH (node, json_object(table_update)) {
     589                 :        440 :         struct json *row_update = node->data;
     590                 :            :         struct json *old, *new;
     591                 :            : 
     592         [ -  + ]:        440 :         if (row_update->type != JSON_OBJECT) {
     593                 :          0 :             ovs_error(0, "<row-update> is not object");
     594                 :          0 :             continue;
     595                 :            :         }
     596                 :        440 :         old = shash_find_data(json_object(row_update), "old");
     597                 :        440 :         new = shash_find_data(json_object(row_update), "new");
     598         [ +  + ]:        440 :         if (initial) {
     599                 :         12 :             monitor_print_row(new, "initial", node->name, columns, &t);
     600         [ +  + ]:        428 :         } else if (!old) {
     601                 :        211 :             monitor_print_row(new, "insert", node->name, columns, &t);
     602         [ +  + ]:        217 :         } else if (!new) {
     603                 :        209 :             monitor_print_row(old, "delete", node->name, columns, &t);
     604                 :            :         } else {
     605                 :          8 :             monitor_print_row(old, "old", node->name, columns, &t);
     606                 :          8 :             monitor_print_row(new, "new", "", columns, &t);
     607                 :            :         }
     608                 :            :     }
     609                 :         36 :     table_print(&t, &table_style);
     610                 :         36 :     table_destroy(&t);
     611                 :            : }
     612                 :            : 
     613                 :            : static void
     614                 :         34 : monitor_print(struct json *table_updates,
     615                 :            :               const struct monitored_table *mts, size_t n_mts,
     616                 :            :               bool initial)
     617                 :            : {
     618                 :            :     size_t i;
     619                 :            : 
     620         [ -  + ]:         34 :     if (table_updates->type != JSON_OBJECT) {
     621                 :          0 :         ovs_error(0, "<table-updates> is not object");
     622                 :          0 :         return;
     623                 :            :     }
     624                 :            : 
     625         [ +  + ]:        143 :     for (i = 0; i < n_mts; i++) {
     626                 :        109 :         const struct monitored_table *mt = &mts[i];
     627                 :        109 :         struct json *table_update = shash_find_data(json_object(table_updates),
     628                 :        109 :                                                     mt->table->name);
     629         [ +  + ]:        109 :         if (table_update) {
     630         [ +  + ]:         36 :             monitor_print_table(table_update, mt,
     631                 :         11 :                                 n_mts > 1 ? xstrdup(mt->table->name) : NULL,
     632                 :            :                                 initial);
     633                 :            :         }
     634                 :            :     }
     635                 :            : }
     636                 :            : 
     637                 :            : static void
     638                 :         22 : monitor2_print_row(struct json *row, const char *type, const char *uuid,
     639                 :            :                    const struct ovsdb_column_set *columns, struct table *t)
     640                 :            : {
     641         [ +  + ]:         22 :     if (!strcmp(type, "delete")) {
     642         [ -  + ]:          5 :         if (row->type != JSON_NULL) {
     643                 :          0 :             ovs_error(0, "delete method does not expect <row>");
     644                 :          0 :             return;
     645                 :            :         }
     646                 :            : 
     647                 :          5 :         table_add_row(t);
     648                 :          5 :         table_add_cell(t)->text = xstrdup(uuid);
     649                 :          5 :         table_add_cell(t)->text = xstrdup(type);
     650                 :            :     } else {
     651 [ +  - ][ -  + ]:         17 :         if (!row || row->type != JSON_OBJECT) {
     652                 :          0 :             ovs_error(0, "<row> is not object");
     653                 :          0 :             return;
     654                 :            :         }
     655                 :         17 :         monitor_print_row(row, type, uuid, columns, t);
     656                 :            :     }
     657                 :            : }
     658                 :            : 
     659                 :            : static void
     660                 :         15 : monitor2_print_table(struct json *table_update2,
     661                 :            :                     const struct monitored_table *mt, char *caption)
     662                 :            : {
     663                 :         15 :     const struct ovsdb_table_schema *table = mt->table;
     664                 :         15 :     const struct ovsdb_column_set *columns = &mt->columns;
     665                 :            :     struct shash_node *node;
     666                 :            :     struct table t;
     667                 :            : 
     668         [ -  + ]:         15 :     if (table_update2->type != JSON_OBJECT) {
     669                 :          0 :         ovs_error(0, "<table-update> for table %s is not object", table->name);
     670                 :          0 :         return;
     671                 :            :     }
     672                 :            : 
     673                 :         15 :     table_init(&t);
     674                 :         15 :     table_set_timestamp(&t, timestamp);
     675                 :         15 :     table_set_caption(&t, caption);
     676                 :            : 
     677                 :         15 :     table_add_column(&t, "row");
     678                 :         15 :     table_add_column(&t, "action");
     679         [ +  + ]:         56 :     for (size_t i = 0; i < columns->n_columns; i++) {
     680                 :         41 :         table_add_column(&t, "%s", columns->columns[i]->name);
     681                 :            :     }
     682 [ +  + ][ -  + ]:         37 :     SHASH_FOR_EACH (node, json_object(table_update2)) {
     683                 :         22 :         struct json *row_update2 = node->data;
     684                 :            :         const char *operation;
     685                 :            :         struct json *row;
     686                 :         22 :         const char *ops[] = {"delete", "initial", "modify", "insert"};
     687                 :            : 
     688         [ -  + ]:         22 :         if (row_update2->type != JSON_OBJECT) {
     689                 :          0 :             ovs_error(0, "<row-update2> is not object");
     690                 :          0 :             continue;
     691                 :            :         }
     692                 :            : 
     693                 :            :         /* row_update2 contains one of objects indexed by ops[] */
     694         [ +  - ]:         77 :         for (int i = 0; i < ARRAY_SIZE(ops); i++) {
     695                 :         55 :             operation = ops[i];
     696                 :         55 :             row = shash_find_data(json_object(row_update2), operation);
     697                 :            : 
     698         [ +  + ]:         55 :             if (row) {
     699                 :         22 :                 monitor2_print_row(row, operation, node->name, columns, &t);
     700                 :         22 :                 break;
     701                 :            :             }
     702                 :            :         }
     703                 :            :     }
     704                 :         15 :     table_print(&t, &table_style);
     705                 :         15 :     table_destroy(&t);
     706                 :            : }
     707                 :            : 
     708                 :            : static void
     709                 :         17 : monitor2_print(struct json *table_updates2,
     710                 :            :                const struct monitored_table *mts, size_t n_mts)
     711                 :            : {
     712                 :            :     size_t i;
     713                 :            : 
     714         [ -  + ]:         17 :     if (table_updates2->type != JSON_OBJECT) {
     715                 :          0 :         ovs_error(0, "<table-updates2> is not object");
     716                 :          0 :         return;
     717                 :            :     }
     718                 :            : 
     719         [ +  + ]:         34 :     for (i = 0; i < n_mts; i++) {
     720                 :         17 :         const struct monitored_table *mt = &mts[i];
     721                 :         17 :         struct json *table_update = shash_find_data(
     722                 :         17 :                                         json_object(table_updates2),
     723                 :         17 :                                         mt->table->name);
     724         [ +  + ]:         17 :         if (table_update) {
     725         [ -  + ]:         15 :             monitor2_print_table(table_update, mt,
     726                 :          0 :                                 n_mts > 1 ? xstrdup(mt->table->name) : NULL);
     727                 :            :         }
     728                 :            :     }
     729                 :            : }
     730                 :            : 
     731                 :            : static void
     732                 :        246 : add_column(const char *server, const struct ovsdb_column *column,
     733                 :            :            struct ovsdb_column_set *columns, struct json *columns_json)
     734                 :            : {
     735         [ -  + ]:        246 :     if (ovsdb_column_set_contains(columns, column->index)) {
     736                 :          0 :         ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
     737                 :            :                   server, column->name);
     738                 :            :     }
     739                 :        246 :     ovsdb_column_set_add(columns, column);
     740                 :        246 :     json_array_add(columns_json, json_string_create(column->name));
     741                 :        246 : }
     742                 :            : 
     743                 :            : static struct json *
     744                 :         37 : parse_monitor_columns(char *arg, const char *server, const char *database,
     745                 :            :                       const struct ovsdb_table_schema *table,
     746                 :            :                       struct ovsdb_column_set *columns)
     747                 :            : {
     748                 :            :     bool initial, insert, delete, modify;
     749                 :            :     struct json *mr, *columns_json;
     750                 :         37 :     char *save_ptr = NULL;
     751                 :            :     char *token;
     752                 :            : 
     753                 :         37 :     mr = json_object_create();
     754                 :         37 :     columns_json = json_array_create_empty();
     755                 :         37 :     json_object_put(mr, "columns", columns_json);
     756                 :            : 
     757                 :         37 :     initial = insert = delete = modify = true;
     758         [ +  + ]:         56 :     for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
     759                 :         19 :          token = strtok_r(NULL, ",", &save_ptr)) {
     760         [ +  + ]:         19 :         if (!strcmp(token, "!initial")) {
     761                 :          5 :             initial = false;
     762         [ +  + ]:         14 :         } else if (!strcmp(token, "!insert")) {
     763                 :          4 :             insert = false;
     764         [ +  + ]:         10 :         } else if (!strcmp(token, "!delete")) {
     765                 :          4 :             delete = false;
     766         [ +  + ]:          6 :         } else if (!strcmp(token, "!modify")) {
     767                 :          5 :             modify = false;
     768                 :            :         } else {
     769                 :            :             const struct ovsdb_column *column;
     770                 :            : 
     771                 :          1 :             column = ovsdb_table_schema_get_column(table, token);
     772         [ -  + ]:          1 :             if (!column) {
     773                 :          0 :                 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
     774                 :            :                           "column named \"%s\"",
     775                 :            :                           server, table->name, database, token);
     776                 :            :             }
     777                 :          1 :             add_column(server, column, columns, columns_json);
     778                 :            :         }
     779                 :            :     }
     780                 :            : 
     781         [ +  + ]:         37 :     if (columns_json->u.array.n == 0) {
     782                 :            :         const struct shash_node **nodes;
     783                 :            :         size_t i, n;
     784                 :            : 
     785                 :         36 :         n = shash_count(&table->columns);
     786                 :         36 :         nodes = shash_sort(&table->columns);
     787         [ +  + ]:        317 :         for (i = 0; i < n; i++) {
     788                 :        281 :             const struct ovsdb_column *column = nodes[i]->data;
     789         [ +  + ]:        281 :             if (column->index != OVSDB_COL_UUID
     790         [ +  + ]:        245 :                 && column->index != OVSDB_COL_VERSION) {
     791                 :        209 :                 add_column(server, column, columns, columns_json);
     792                 :            :             }
     793                 :            :         }
     794                 :         36 :         free(nodes);
     795                 :            : 
     796                 :         36 :         add_column(server, ovsdb_table_schema_get_column(table, "_version"),
     797                 :            :                    columns, columns_json);
     798                 :            :     }
     799                 :            : 
     800 [ +  + ][ +  + ]:         37 :     if (!initial || !insert || !delete || !modify) {
         [ +  - ][ -  + ]
     801                 :          6 :         struct json *select = json_object_create();
     802                 :          6 :         json_object_put(select, "initial", json_boolean_create(initial));
     803                 :          6 :         json_object_put(select, "insert", json_boolean_create(insert));
     804                 :          6 :         json_object_put(select, "delete", json_boolean_create(delete));
     805                 :          6 :         json_object_put(select, "modify", json_boolean_create(modify));
     806                 :          6 :         json_object_put(mr, "select", select);
     807                 :            :     }
     808                 :            : 
     809                 :         37 :     return mr;
     810                 :            : }
     811                 :            : 
     812                 :            : static void
     813                 :          1 : ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
     814                 :            :                   const char *argv[] OVS_UNUSED, void *exiting_)
     815                 :            : {
     816                 :          1 :     bool *exiting = exiting_;
     817                 :          1 :     *exiting = true;
     818                 :          1 :     unixctl_command_reply(conn, NULL);
     819                 :          1 : }
     820                 :            : 
     821                 :            : static void
     822                 :          1 : ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
     823                 :            :                    const char *argv[] OVS_UNUSED, void *blocked_)
     824                 :            : {
     825                 :          1 :     bool *blocked = blocked_;
     826                 :            : 
     827         [ +  - ]:          1 :     if (!*blocked) {
     828                 :          1 :         *blocked = true;
     829                 :          1 :         unixctl_command_reply(conn, NULL);
     830                 :            :     } else {
     831                 :          0 :         unixctl_command_reply(conn, "already blocking");
     832                 :            :     }
     833                 :          1 : }
     834                 :            : 
     835                 :            : static void
     836                 :          1 : ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
     837                 :            :                      const char *argv[] OVS_UNUSED, void *blocked_)
     838                 :            : {
     839                 :          1 :     bool *blocked = blocked_;
     840                 :            : 
     841         [ +  - ]:          1 :     if (*blocked) {
     842                 :          1 :         *blocked = false;
     843                 :          1 :         unixctl_command_reply(conn, NULL);
     844                 :            :     } else {
     845                 :          0 :         unixctl_command_reply(conn, "already unblocked");
     846                 :            :     }
     847                 :          1 : }
     848                 :            : 
     849                 :            : static void
     850                 :          4 : ovsdb_client_cond_change(struct unixctl_conn *conn, int argc OVS_UNUSED,
     851                 :            :                      const char *argv[], void *rpc_)
     852                 :            : {
     853                 :          4 :     struct jsonrpc *rpc = rpc_;
     854                 :          4 :     struct json *monitor_cond_update_requests = json_object_create();
     855                 :          4 :     struct json *monitor_cond_update_request = json_object_create();
     856                 :            :     struct json *params;
     857                 :            :     struct jsonrpc_msg *request;
     858                 :            : 
     859                 :          4 :     json_object_put(monitor_cond_update_request, "where",
     860                 :          4 :                     json_from_string(argv[2]));
     861                 :          4 :     json_object_put(monitor_cond_update_requests,
     862                 :          4 :                     argv[1],
     863                 :            :                     json_array_create_1(monitor_cond_update_request));
     864                 :            : 
     865                 :          4 :     params = json_array_create_3(json_null_create(),json_null_create(),
     866                 :            :                                  monitor_cond_update_requests);
     867                 :            : 
     868                 :          4 :     request = jsonrpc_create_request("monitor_cond_change", params, NULL);
     869                 :          4 :     jsonrpc_send(rpc, request);
     870                 :            : 
     871         [ -  + ]:          4 :     VLOG_DBG("cond change %s %s", argv[1], argv[2]);
     872                 :          4 :     unixctl_command_reply(conn, "condiiton changed");
     873                 :          4 : }
     874                 :            : 
     875                 :            : static void
     876                 :         37 : add_monitored_table(int argc, char *argv[],
     877                 :            :                     const char *server, const char *database,
     878                 :            :                     struct json *condition,
     879                 :            :                     struct ovsdb_table_schema *table,
     880                 :            :                     struct json *monitor_requests,
     881                 :            :                     struct monitored_table **mts,
     882                 :            :                     size_t *n_mts, size_t *allocated_mts)
     883                 :            : {
     884                 :            :     struct json *monitor_request_array, *mr;
     885                 :            :     struct monitored_table *mt;
     886                 :            : 
     887         [ +  + ]:         37 :     if (*n_mts >= *allocated_mts) {
     888                 :         26 :         *mts = x2nrealloc(*mts, allocated_mts, sizeof **mts);
     889                 :            :     }
     890                 :         37 :     mt = &(*mts)[(*n_mts)++];
     891                 :         37 :     mt->table = table;
     892                 :         37 :     ovsdb_column_set_init(&mt->columns);
     893                 :            : 
     894                 :         37 :     monitor_request_array = json_array_create_empty();
     895         [ +  + ]:         37 :     if (argc > 1) {
     896                 :            :         int i;
     897                 :            : 
     898         [ +  + ]:         14 :         for (i = 1; i < argc; i++) {
     899                 :          7 :             mr = parse_monitor_columns(argv[i], server, database, table,
     900                 :            :                                        &mt->columns);
     901 [ +  - ][ +  + ]:          7 :             if (i == 1 && condition) {
     902                 :          3 :                 json_object_put(mr, "where", condition);
     903                 :            :             }
     904                 :          7 :             json_array_add(monitor_request_array, mr);
     905                 :            :         }
     906                 :            :     } else {
     907                 :            :         /* Allocate a writable empty string since parse_monitor_columns()
     908                 :            :          * is going to strtok() it and that's risky with literal "". */
     909                 :         30 :         char empty[] = "";
     910                 :            : 
     911                 :         30 :         mr = parse_monitor_columns(empty, server, database,
     912                 :            :                                    table, &mt->columns);
     913         [ +  + ]:         30 :         if (condition) {
     914                 :          4 :             json_object_put(mr, "where", condition);
     915                 :            :         }
     916                 :         30 :         json_array_add(monitor_request_array, mr);
     917                 :            :     }
     918                 :            : 
     919                 :         37 :     json_object_put(monitor_requests, table->name, monitor_request_array);
     920                 :         37 : }
     921                 :            : 
     922                 :            : static void
     923                 :          1 : destroy_monitored_table(struct monitored_table *mts, size_t n)
     924                 :            : {
     925                 :            :     int i;
     926                 :            : 
     927         [ +  + ]:         17 :     for (i = 0; i < n; i++) {
     928                 :         16 :         struct monitored_table *mt = &mts[i];
     929                 :         16 :         ovsdb_column_set_destroy(&mt->columns);
     930                 :            :     }
     931                 :            : 
     932                 :          1 :     free(mts);
     933                 :          1 : }
     934                 :            : 
     935                 :            : static void
     936                 :         23 : do_monitor__(struct jsonrpc *rpc, const char *database,
     937                 :            :              enum ovsdb_monitor_version version,
     938                 :            :              int argc, char *argv[], struct json *condition)
     939                 :            : {
     940                 :         23 :     const char *server = jsonrpc_get_name(rpc);
     941                 :         23 :     const char *table_name = argv[0];
     942                 :            :     struct unixctl_server *unixctl;
     943                 :            :     struct ovsdb_schema *schema;
     944                 :            :     struct jsonrpc_msg *request;
     945                 :            :     struct json *monitor, *monitor_requests, *request_id;
     946                 :         23 :     bool exiting = false;
     947                 :         23 :     bool blocked = false;
     948                 :            : 
     949                 :            :     struct monitored_table *mts;
     950                 :            :     size_t n_mts, allocated_mts;
     951                 :            : 
     952         [ -  + ]:         23 :     ovs_assert(version < OVSDB_MONITOR_VERSION_MAX);
     953                 :            : 
     954                 :         23 :     daemon_save_fd(STDOUT_FILENO);
     955                 :         23 :     daemonize_start(false);
     956         [ +  - ]:         22 :     if (get_detach()) {
     957                 :            :         int error;
     958                 :            : 
     959                 :         22 :         error = unixctl_server_create(NULL, &unixctl);
     960         [ -  + ]:         22 :         if (error) {
     961                 :          0 :             ovs_fatal(error, "failed to create unixctl server");
     962                 :            :         }
     963                 :            : 
     964                 :         22 :         unixctl_command_register("exit", "", 0, 0,
     965                 :            :                                  ovsdb_client_exit, &exiting);
     966                 :         22 :         unixctl_command_register("ovsdb-client/block", "", 0, 0,
     967                 :            :                                  ovsdb_client_block, &blocked);
     968                 :         22 :         unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
     969                 :            :                                  ovsdb_client_unblock, &blocked);
     970                 :         22 :         unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
     971                 :            :                                  ovsdb_client_cond_change, rpc);
     972                 :            :     } else {
     973                 :          0 :         unixctl = NULL;
     974                 :            :     }
     975                 :            : 
     976                 :         22 :     schema = fetch_schema(rpc, database);
     977                 :            : 
     978                 :         22 :     monitor_requests = json_object_create();
     979                 :            : 
     980                 :         22 :     mts = NULL;
     981                 :         22 :     n_mts = allocated_mts = 0;
     982         [ +  + ]:         22 :     if (strcmp(table_name, "ALL")) {
     983                 :            :         struct ovsdb_table_schema *table;
     984                 :            : 
     985                 :         21 :         table = shash_find_data(&schema->tables, table_name);
     986         [ -  + ]:         21 :         if (!table) {
     987                 :          0 :             ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
     988                 :            :                       server, database, table_name);
     989                 :            :         }
     990                 :            : 
     991                 :         21 :         add_monitored_table(argc, argv, server, database, condition, table,
     992                 :            :                             monitor_requests, &mts, &n_mts, &allocated_mts);
     993                 :            :     } else {
     994                 :          1 :         size_t n = shash_count(&schema->tables);
     995                 :          1 :         const struct shash_node **nodes = shash_sort(&schema->tables);
     996                 :            :         size_t i;
     997                 :            : 
     998         [ -  + ]:          1 :         if (condition) {
     999                 :          0 :             ovs_fatal(0, "ALL tables are not allowed with condition");
    1000                 :            :         }
    1001                 :            : 
    1002         [ +  + ]:         17 :         for (i = 0; i < n; i++) {
    1003                 :         16 :             struct ovsdb_table_schema *table = nodes[i]->data;
    1004                 :            : 
    1005                 :         16 :             add_monitored_table(argc, argv, server, database, NULL, table,
    1006                 :            :                                 monitor_requests,
    1007                 :            :                                 &mts, &n_mts, &allocated_mts);
    1008                 :            :         }
    1009                 :          1 :         free(nodes);
    1010                 :            :     }
    1011                 :            : 
    1012                 :         22 :     monitor = json_array_create_3(json_string_create(database),
    1013                 :            :                                   json_null_create(), monitor_requests);
    1014                 :         22 :     const char *method = version == OVSDB_MONITOR_V2 ? "monitor_cond"
    1015         [ +  + ]:         22 :                                                      : "monitor";
    1016                 :            : 
    1017                 :         22 :     request = jsonrpc_create_request(method, monitor, NULL);
    1018                 :         22 :     request_id = json_clone(request->id);
    1019                 :         22 :     jsonrpc_send(rpc, request);
    1020                 :            : 
    1021                 :            :     for (;;) {
    1022                 :        117 :         unixctl_server_run(unixctl);
    1023         [ +  + ]:        172 :         while (!blocked) {
    1024                 :            :             struct jsonrpc_msg *msg;
    1025                 :            :             int error;
    1026                 :            : 
    1027                 :        169 :             error = jsonrpc_recv(rpc, &msg);
    1028         [ +  + ]:        169 :             if (error == EAGAIN) {
    1029                 :         93 :                 break;
    1030         [ +  + ]:         76 :             } else if (error) {
    1031                 :         21 :                 ovs_fatal(error, "%s: receive failed", server);
    1032                 :            :             }
    1033                 :            : 
    1034 [ -  + ][ #  # ]:         55 :             if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
    1035                 :          0 :                 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
    1036                 :          0 :                                                        msg->id));
    1037         [ +  + ]:         55 :             } else if (msg->type == JSONRPC_REPLY
    1038         [ +  + ]:         26 :                        && json_equal(msg->id, request_id)) {
    1039      [ +  +  - ]:         22 :                 switch(version) {
    1040                 :            :                 case OVSDB_MONITOR_V1:
    1041                 :         15 :                     monitor_print(msg->result, mts, n_mts, true);
    1042                 :         15 :                     break;
    1043                 :            :                 case OVSDB_MONITOR_V2:
    1044                 :          7 :                     monitor2_print(msg->result, mts, n_mts);
    1045                 :          7 :                     break;
    1046                 :            :                 case OVSDB_MONITOR_VERSION_MAX:
    1047                 :            :                 default:
    1048                 :          0 :                     OVS_NOT_REACHED();
    1049                 :            :                 }
    1050                 :         22 :                 fflush(stdout);
    1051                 :         22 :                 daemonize_complete();
    1052         [ +  + ]:         33 :             } else if (msg->type == JSONRPC_NOTIFY
    1053         [ +  + ]:         48 :                        && !strcmp(msg->method, "update")) {
    1054                 :         19 :                 struct json *params = msg->params;
    1055         [ +  - ]:         19 :                 if (params->type == JSON_ARRAY
    1056         [ +  - ]:         19 :                     && params->u.array.n == 2
    1057         [ +  - ]:         19 :                     && params->u.array.elems[0]->type == JSON_NULL) {
    1058                 :         19 :                     monitor_print(params->u.array.elems[1], mts, n_mts, false);
    1059                 :         19 :                     fflush(stdout);
    1060                 :            :                 }
    1061         [ +  + ]:         14 :             } else if (msg->type == JSONRPC_NOTIFY
    1062         [ +  - ]:         10 :                        && version == OVSDB_MONITOR_V2
    1063         [ +  - ]:         10 :                        && !strcmp(msg->method, "update2")) {
    1064                 :         10 :                 struct json *params = msg->params;
    1065         [ +  - ]:         10 :                 if (params->type == JSON_ARRAY
    1066         [ +  - ]:         10 :                     && params->u.array.n == 2
    1067         [ +  - ]:         10 :                     && params->u.array.elems[0]->type == JSON_NULL) {
    1068                 :         10 :                     monitor2_print(params->u.array.elems[1], mts, n_mts);
    1069                 :         10 :                     fflush(stdout);
    1070                 :            :                 }
    1071                 :            :             }
    1072                 :         55 :             jsonrpc_msg_destroy(msg);
    1073                 :            :         }
    1074                 :            : 
    1075         [ +  + ]:         96 :         if (exiting) {
    1076                 :          1 :             break;
    1077                 :            :         }
    1078                 :            : 
    1079                 :         95 :         jsonrpc_run(rpc);
    1080                 :         95 :         jsonrpc_wait(rpc);
    1081         [ +  + ]:         95 :         if (!blocked) {
    1082                 :         92 :             jsonrpc_recv_wait(rpc);
    1083                 :            :         }
    1084                 :         95 :         unixctl_server_wait(unixctl);
    1085                 :         95 :         poll_block();
    1086                 :         95 :     }
    1087                 :            : 
    1088                 :          1 :     json_destroy(request_id);
    1089                 :          1 :     unixctl_server_destroy(unixctl);
    1090                 :          1 :     ovsdb_schema_destroy(schema);
    1091                 :          1 :     destroy_monitored_table(mts, n_mts);
    1092                 :          1 : }
    1093                 :            : 
    1094                 :            : static void
    1095                 :         16 : do_monitor(struct jsonrpc *rpc, const char *database,
    1096                 :            :            int argc, char *argv[])
    1097                 :            : {
    1098                 :         16 :     do_monitor__(rpc, database, OVSDB_MONITOR_V1, argc, argv, NULL);
    1099                 :          1 : }
    1100                 :            : 
    1101                 :            : static void
    1102                 :          7 : do_monitor_cond(struct jsonrpc *rpc, const char *database,
    1103                 :            :            int argc, char *argv[])
    1104                 :            : {
    1105                 :            :     struct ovsdb_condition cnd;
    1106                 :          7 :     struct json *condition = NULL;
    1107                 :            :     struct ovsdb_schema *schema;
    1108                 :            :     struct ovsdb_table_schema *table;
    1109                 :          7 :     const char *table_name = argv[1];
    1110                 :            : 
    1111         [ -  + ]:          7 :     ovs_assert(argc > 1);
    1112                 :          7 :     schema = fetch_schema(rpc, database);
    1113                 :          7 :     table = shash_find_data(&schema->tables, table_name);
    1114         [ -  + ]:          7 :     if (!table) {
    1115                 :          0 :         ovs_fatal(0, "%s does not have a table named \"%s\"",
    1116                 :            :                   database, table_name);
    1117                 :            :     }
    1118                 :          7 :     condition = parse_json(argv[0]);
    1119                 :          7 :     check_ovsdb_error(ovsdb_condition_from_json(table, condition,
    1120                 :            :                                                     NULL, &cnd));
    1121                 :          7 :     ovsdb_condition_destroy(&cnd);
    1122                 :          7 :     do_monitor__(rpc, database, OVSDB_MONITOR_V2, --argc, ++argv, condition);
    1123                 :          0 :     ovsdb_schema_destroy(schema);
    1124                 :          0 : }
    1125                 :            : 
    1126                 :            : struct dump_table_aux {
    1127                 :            :     struct ovsdb_datum **data;
    1128                 :            :     const struct ovsdb_column **columns;
    1129                 :            :     size_t n_columns;
    1130                 :            : };
    1131                 :            : 
    1132                 :            : static int
    1133                 :        198 : compare_data(size_t a_y, size_t b_y, size_t x,
    1134                 :            :              const struct dump_table_aux *aux)
    1135                 :            : {
    1136                 :        198 :     return ovsdb_datum_compare_3way(&aux->data[a_y][x],
    1137                 :        198 :                                     &aux->data[b_y][x],
    1138                 :        198 :                                     &aux->columns[x]->type);
    1139                 :            : }
    1140                 :            : 
    1141                 :            : static int
    1142                 :        180 : compare_rows(size_t a_y, size_t b_y, void *aux_)
    1143                 :            : {
    1144                 :        180 :     struct dump_table_aux *aux = aux_;
    1145                 :            :     size_t x;
    1146                 :            : 
    1147                 :            :     /* Skip UUID columns on the first pass, since their values tend to be
    1148                 :            :      * random and make our results less reproducible. */
    1149         [ +  - ]:        378 :     for (x = 0; x < aux->n_columns; x++) {
    1150         [ +  + ]:        378 :         if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
    1151                 :        198 :             int cmp = compare_data(a_y, b_y, x, aux);
    1152         [ +  + ]:        198 :             if (cmp) {
    1153                 :        180 :                 return cmp;
    1154                 :            :             }
    1155                 :            :         }
    1156                 :            :     }
    1157                 :            : 
    1158                 :            :     /* Use UUID columns as tie-breakers. */
    1159         [ #  # ]:          0 :     for (x = 0; x < aux->n_columns; x++) {
    1160         [ #  # ]:          0 :         if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
    1161                 :          0 :             int cmp = compare_data(a_y, b_y, x, aux);
    1162         [ #  # ]:          0 :             if (cmp) {
    1163                 :          0 :                 return cmp;
    1164                 :            :             }
    1165                 :            :         }
    1166                 :            :     }
    1167                 :            : 
    1168                 :          0 :     return 0;
    1169                 :            : }
    1170                 :            : 
    1171                 :            : static void
    1172                 :        262 : swap_rows(size_t a_y, size_t b_y, void *aux_)
    1173                 :            : {
    1174                 :        262 :     struct dump_table_aux *aux = aux_;
    1175                 :        262 :     struct ovsdb_datum *tmp = aux->data[a_y];
    1176                 :        262 :     aux->data[a_y] = aux->data[b_y];
    1177                 :        262 :     aux->data[b_y] = tmp;
    1178                 :        262 : }
    1179                 :            : 
    1180                 :            : static int
    1181                 :        473 : compare_columns(const void *a_, const void *b_)
    1182                 :            : {
    1183                 :        473 :     const struct ovsdb_column *const *ap = a_;
    1184                 :        473 :     const struct ovsdb_column *const *bp = b_;
    1185                 :        473 :     const struct ovsdb_column *a = *ap;
    1186                 :        473 :     const struct ovsdb_column *b = *bp;
    1187                 :            : 
    1188                 :        473 :     return strcmp(a->name, b->name);
    1189                 :            : }
    1190                 :            : 
    1191                 :            : static void
    1192                 :        145 : dump_table(const char *table_name, const struct shash *cols,
    1193                 :            :            struct json_array *rows)
    1194                 :            : {
    1195                 :            :     const struct ovsdb_column **columns;
    1196                 :            :     size_t n_columns;
    1197                 :            : 
    1198                 :            :     struct ovsdb_datum **data;
    1199                 :            : 
    1200                 :            :     struct dump_table_aux aux;
    1201                 :            :     struct shash_node *node;
    1202                 :            :     struct table t;
    1203                 :            :     size_t x, y;
    1204                 :            : 
    1205                 :            :     /* Sort columns by name, for reproducibility. */
    1206                 :        145 :     columns = xmalloc(shash_count(cols) * sizeof *columns);
    1207                 :        145 :     n_columns = 0;
    1208 [ +  + ][ -  + ]:        743 :     SHASH_FOR_EACH (node, cols) {
    1209                 :        598 :         struct ovsdb_column *column = node->data;
    1210         [ +  + ]:        598 :         if (strcmp(column->name, "_version")) {
    1211                 :        453 :             columns[n_columns++] = column;
    1212                 :            :         }
    1213                 :            :     }
    1214                 :        145 :     qsort(columns, n_columns, sizeof *columns, compare_columns);
    1215                 :            : 
    1216                 :            :     /* Extract data from table. */
    1217                 :        145 :     data = xmalloc(rows->n * sizeof *data);
    1218         [ +  + ]:        306 :     for (y = 0; y < rows->n; y++) {
    1219                 :            :         struct shash *row;
    1220                 :            : 
    1221         [ -  + ]:        161 :         if (rows->elems[y]->type != JSON_OBJECT) {
    1222                 :          0 :             ovs_fatal(0,  "row %"PRIuSIZE" in table %s response is not a JSON object: "
    1223                 :          0 :                       "%s", y, table_name, json_to_string(rows->elems[y], 0));
    1224                 :            :         }
    1225                 :        161 :         row = json_object(rows->elems[y]);
    1226                 :            : 
    1227                 :        161 :         data[y] = xmalloc(n_columns * sizeof **data);
    1228         [ +  + ]:        628 :         for (x = 0; x < n_columns; x++) {
    1229                 :        467 :             const struct json *json = shash_find_data(row, columns[x]->name);
    1230         [ -  + ]:        467 :             if (!json) {
    1231                 :          0 :                 ovs_fatal(0, "row %"PRIuSIZE" in table %s response lacks %s column",
    1232                 :          0 :                           y, table_name, columns[x]->name);
    1233                 :            :             }
    1234                 :            : 
    1235                 :        467 :             check_ovsdb_error(ovsdb_datum_from_json(&data[y][x],
    1236                 :        467 :                                                     &columns[x]->type,
    1237                 :            :                                                     json, NULL));
    1238                 :            :         }
    1239                 :            :     }
    1240                 :            : 
    1241                 :            :     /* Sort rows by column values, for reproducibility. */
    1242                 :        145 :     aux.data = data;
    1243                 :        145 :     aux.columns = columns;
    1244                 :        145 :     aux.n_columns = n_columns;
    1245                 :        145 :     sort(rows->n, compare_rows, swap_rows, &aux);
    1246                 :            : 
    1247                 :            :     /* Add column headings. */
    1248                 :        145 :     table_init(&t);
    1249                 :        145 :     table_set_caption(&t, xasprintf("%s table", table_name));
    1250         [ +  + ]:        598 :     for (x = 0; x < n_columns; x++) {
    1251                 :        453 :         table_add_column(&t, "%s", columns[x]->name);
    1252                 :            :     }
    1253                 :            : 
    1254                 :            :     /* Print rows. */
    1255         [ +  + ]:        306 :     for (y = 0; y < rows->n; y++) {
    1256                 :        161 :         table_add_row(&t);
    1257         [ +  + ]:        628 :         for (x = 0; x < n_columns; x++) {
    1258                 :        467 :             struct cell *cell = table_add_cell(&t);
    1259                 :        467 :             cell->json = ovsdb_datum_to_json(&data[y][x], &columns[x]->type);
    1260                 :        467 :             cell->type = &columns[x]->type;
    1261                 :        467 :             ovsdb_datum_destroy(&data[y][x], &columns[x]->type);
    1262                 :            :         }
    1263                 :        161 :         free(data[y]);
    1264                 :            :     }
    1265                 :        145 :     table_print(&t, &table_style);
    1266                 :        145 :     table_destroy(&t);
    1267                 :            : 
    1268                 :        145 :     free(data);
    1269                 :        145 :     free(columns);
    1270                 :        145 : }
    1271                 :            : 
    1272                 :            : static void
    1273                 :         93 : do_dump(struct jsonrpc *rpc, const char *database,
    1274                 :            :         int argc, char *argv[])
    1275                 :            : {
    1276                 :            :     struct jsonrpc_msg *request, *reply;
    1277                 :            :     struct ovsdb_schema *schema;
    1278                 :            :     struct json *transaction;
    1279                 :            : 
    1280                 :            :     const struct shash_node *node, **tables;
    1281                 :            :     size_t n_tables;
    1282                 :            :     struct ovsdb_table_schema *tschema;
    1283                 :            :     const struct shash *columns;
    1284                 :            :     struct shash custom_columns;
    1285                 :            : 
    1286                 :            :     size_t i;
    1287                 :            : 
    1288                 :         93 :     shash_init(&custom_columns);
    1289                 :         93 :     schema = fetch_schema(rpc, database);
    1290         [ -  + ]:         93 :     if (argc) {
    1291                 :          0 :         node = shash_find(&schema->tables, argv[0]);
    1292         [ #  # ]:          0 :         if (!node) {
    1293                 :          0 :             ovs_fatal(0, "No table \"%s\" found.", argv[0]);
    1294                 :            :         }
    1295                 :          0 :         tables = xmemdup(&node, sizeof(&node));
    1296                 :          0 :         n_tables = 1;
    1297                 :          0 :         tschema = tables[0]->data;
    1298         [ #  # ]:          0 :         for (i = 1; i < argc; i++) {
    1299                 :          0 :             node = shash_find(&tschema->columns, argv[i]);
    1300         [ #  # ]:          0 :             if (!node) {
    1301                 :          0 :                 ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[1]);
    1302                 :            :             }
    1303                 :          0 :             shash_add(&custom_columns, argv[1], node->data);
    1304                 :            :         }
    1305                 :            :     } else {
    1306                 :         93 :         tables = shash_sort(&schema->tables);
    1307                 :         93 :         n_tables = shash_count(&schema->tables);
    1308                 :            :     }
    1309                 :            : 
    1310                 :            :     /* Construct transaction to retrieve entire database. */
    1311                 :         93 :     transaction = json_array_create_1(json_string_create(database));
    1312         [ +  + ]:        238 :     for (i = 0; i < n_tables; i++) {
    1313                 :        145 :         const struct ovsdb_table_schema *ts = tables[i]->data;
    1314                 :            :         struct json *op, *jcolumns;
    1315                 :            : 
    1316         [ -  + ]:        145 :         if (argc > 1) {
    1317                 :          0 :             columns = &custom_columns;
    1318                 :            :         } else {
    1319                 :        145 :             columns = &ts->columns;
    1320                 :            :         }
    1321                 :        145 :         jcolumns = json_array_create_empty();
    1322 [ +  + ][ -  + ]:        743 :         SHASH_FOR_EACH (node, columns) {
    1323                 :        598 :             const struct ovsdb_column *column = node->data;
    1324                 :            : 
    1325         [ +  + ]:        598 :             if (strcmp(column->name, "_version")) {
    1326                 :        453 :                 json_array_add(jcolumns, json_string_create(column->name));
    1327                 :            :             }
    1328                 :            :         }
    1329                 :            : 
    1330                 :        145 :         op = json_object_create();
    1331                 :        145 :         json_object_put_string(op, "op", "select");
    1332                 :        145 :         json_object_put_string(op, "table", tables[i]->name);
    1333                 :        145 :         json_object_put(op, "where", json_array_create_empty());
    1334                 :        145 :         json_object_put(op, "columns", jcolumns);
    1335                 :        145 :         json_array_add(transaction, op);
    1336                 :            :     }
    1337                 :            : 
    1338                 :            :     /* Send request, get reply. */
    1339                 :         93 :     request = jsonrpc_create_request("transact", transaction, NULL);
    1340                 :         93 :     check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
    1341                 :            : 
    1342                 :            :     /* Print database contents. */
    1343         [ +  - ]:         93 :     if (reply->result->type != JSON_ARRAY
    1344         [ -  + ]:         93 :         || reply->result->u.array.n != n_tables) {
    1345                 :          0 :         ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
    1346                 :          0 :                   n_tables, json_to_string(reply->result, 0));
    1347                 :            :     }
    1348         [ +  + ]:        238 :     for (i = 0; i < n_tables; i++) {
    1349                 :        145 :         const struct ovsdb_table_schema *ts = tables[i]->data;
    1350                 :        145 :         const struct json *op_result = reply->result->u.array.elems[i];
    1351                 :            :         struct json *rows;
    1352                 :            : 
    1353         [ +  - ]:        145 :         if (op_result->type != JSON_OBJECT
    1354         [ +  - ]:        145 :             || !(rows = shash_find_data(json_object(op_result), "rows"))
    1355         [ -  + ]:        145 :             || rows->type != JSON_ARRAY) {
    1356                 :          0 :             ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
    1357                 :            :                       "member array: %s",
    1358                 :            :                       ts->name, json_to_string(op_result, 0));
    1359                 :            :         }
    1360                 :            : 
    1361         [ -  + ]:        145 :         if (argc > 1) {
    1362                 :          0 :             dump_table(tables[i]->name, &custom_columns, &rows->u.array);
    1363                 :            :         } else {
    1364                 :        145 :             dump_table(tables[i]->name, &ts->columns, &rows->u.array);
    1365                 :            :         }
    1366                 :            :     }
    1367                 :            : 
    1368                 :         93 :     jsonrpc_msg_destroy(reply);
    1369                 :         93 :     shash_destroy(&custom_columns);
    1370                 :         93 :     free(tables);
    1371                 :         93 :     ovsdb_schema_destroy(schema);
    1372                 :         93 : }
    1373                 :            : 
    1374                 :            : static void
    1375                 :          0 : do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
    1376                 :            :         int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
    1377                 :            : {
    1378                 :          0 :     usage();
    1379                 :            : }
    1380                 :            : 
    1381                 :            : 
    1382                 :            : /* "lock" command. */
    1383                 :            : 
    1384                 :            : struct ovsdb_client_lock_req {
    1385                 :            :     const char *method;
    1386                 :            :     char *lock;
    1387                 :            : };
    1388                 :            : 
    1389                 :            : static void
    1390                 :          8 : lock_req_init(struct ovsdb_client_lock_req *lock_req,
    1391                 :            :               const char *method, const char *lock_name)
    1392                 :            : {
    1393 [ +  - ][ -  + ]:          8 :     if (lock_req->method || lock_req->lock) {
    1394                 :          0 :         return;
    1395                 :            :     }
    1396                 :          8 :     lock_req->method = method;
    1397                 :          8 :     lock_req->lock = xstrdup(lock_name);
    1398                 :            : }
    1399                 :            : 
    1400                 :            : static bool
    1401                 :         35 : lock_req_is_set(struct ovsdb_client_lock_req *lock_req)
    1402                 :            : {
    1403                 :         35 :     return lock_req->method;
    1404                 :            : }
    1405                 :            : 
    1406                 :            : static void
    1407                 :          8 : lock_req_destroy(struct ovsdb_client_lock_req *lock_req)
    1408                 :            : {
    1409                 :          8 :     free(lock_req->lock);
    1410                 :          8 :     lock_req->method = NULL;
    1411                 :          8 :     lock_req->lock = NULL;
    1412                 :          8 : }
    1413                 :            : 
    1414                 :            : /* Create a lock class request. Caller is responsible for free
    1415                 :            :  * the 'request' message. */
    1416                 :            : static struct jsonrpc_msg *
    1417                 :          8 : create_lock_request(struct ovsdb_client_lock_req *lock_req)
    1418                 :            : {
    1419                 :            :     struct json *locks, *lock;
    1420                 :            : 
    1421                 :          8 :     locks = json_array_create_empty();
    1422                 :          8 :     lock = json_string_create(lock_req->lock);
    1423                 :          8 :     json_array_add(locks, lock);
    1424                 :            : 
    1425                 :          8 :     return jsonrpc_create_request(lock_req->method, locks, NULL);
    1426                 :            : }
    1427                 :            : 
    1428                 :            : static void
    1429                 :          0 : ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED,
    1430                 :            :                   const char *argv[], void *lock_req_)
    1431                 :            : {
    1432                 :          0 :     struct ovsdb_client_lock_req *lock_req = lock_req_;
    1433                 :          0 :     lock_req_init(lock_req, "lock", argv[1]);
    1434                 :          0 :     unixctl_command_reply(conn, NULL);
    1435                 :          0 : }
    1436                 :            : 
    1437                 :            : static void
    1438                 :          2 : ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED,
    1439                 :            :                     const char *argv[], void *lock_req_)
    1440                 :            : {
    1441                 :          2 :     struct ovsdb_client_lock_req *lock_req = lock_req_;
    1442                 :          2 :     lock_req_init(lock_req, "unlock", argv[1]);
    1443                 :          2 :     unixctl_command_reply(conn, NULL);
    1444                 :          2 : }
    1445                 :            : 
    1446                 :            : static void
    1447                 :          0 : ovsdb_client_steal(struct unixctl_conn *conn, int argc OVS_UNUSED,
    1448                 :            :                    const char *argv[], void *lock_req_)
    1449                 :            : {
    1450                 :          0 :     struct ovsdb_client_lock_req *lock_req = lock_req_;
    1451                 :          0 :     lock_req_init(lock_req, "steal", argv[1]);
    1452                 :          0 :     unixctl_command_reply(conn, NULL);
    1453                 :          0 : }
    1454                 :            : 
    1455                 :            : static void
    1456                 :          6 : do_lock(struct jsonrpc *rpc, const char *method, const char *lock)
    1457                 :            : {
    1458                 :          6 :     struct ovsdb_client_lock_req lock_req = {NULL, NULL};
    1459                 :            :     struct unixctl_server *unixctl;
    1460                 :            :     struct jsonrpc_msg *request;
    1461                 :          6 :     struct json *request_id = NULL;
    1462                 :          6 :     bool exiting = false;
    1463                 :          6 :     bool enable_lock_request = true; /* Don't send another request before
    1464                 :            :                                         getting a reply of the previous
    1465                 :            :                                         request. */
    1466                 :          6 :     daemon_save_fd(STDOUT_FILENO);
    1467                 :          6 :     daemonize_start(false);
    1468                 :          6 :     lock_req_init(&lock_req, method, lock);
    1469                 :            : 
    1470         [ +  - ]:          6 :     if (get_detach()) {
    1471                 :            :         int error;
    1472                 :            : 
    1473                 :          6 :         error = unixctl_server_create(NULL, &unixctl);
    1474         [ -  + ]:          6 :         if (error) {
    1475                 :          0 :             ovs_fatal(error, "failed to create unixctl server");
    1476                 :            :         }
    1477                 :            : 
    1478                 :          6 :         unixctl_command_register("unlock", "LOCK", 1, 1,
    1479                 :            :                                   ovsdb_client_unlock, &lock_req);
    1480                 :          6 :         unixctl_command_register("steal", "LOCK", 1, 1,
    1481                 :            :                                   ovsdb_client_steal, &lock_req);
    1482                 :          6 :         unixctl_command_register("lock", "LOCK", 1, 1,
    1483                 :            :                                   ovsdb_client_lock, &lock_req);
    1484                 :          6 :         unixctl_command_register("exit", "", 0, 0,
    1485                 :            :                                  ovsdb_client_exit, &exiting);
    1486                 :            :     } else {
    1487                 :          0 :         unixctl = NULL;
    1488                 :            :     }
    1489                 :            : 
    1490                 :            :     for (;;) {
    1491                 :            :         struct jsonrpc_msg *msg;
    1492                 :            :         int error;
    1493                 :            : 
    1494                 :         35 :         unixctl_server_run(unixctl);
    1495 [ +  - ][ +  + ]:         35 :         if (enable_lock_request && lock_req_is_set(&lock_req)) {
    1496                 :          8 :             request = create_lock_request(&lock_req);
    1497                 :          8 :             request_id = json_clone(request->id);
    1498                 :          8 :             jsonrpc_send(rpc, request);
    1499                 :          8 :             lock_req_destroy(&lock_req);
    1500                 :            :         }
    1501                 :            : 
    1502                 :         35 :         error = jsonrpc_recv(rpc, &msg);
    1503         [ +  + ]:         35 :         if (error == EAGAIN) {
    1504                 :         18 :             goto no_msg;
    1505         [ +  + ]:         17 :         } else if (error) {
    1506                 :          6 :             ovs_fatal(error, "%s: receive failed", jsonrpc_get_name(rpc));
    1507                 :            :         }
    1508                 :            : 
    1509 [ -  + ][ #  # ]:         11 :         if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
    1510                 :          0 :             jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
    1511                 :          0 :                                                    msg->id));
    1512         [ +  + ]:         11 :         } else if (msg->type == JSONRPC_REPLY
    1513         [ +  - ]:          8 :                    && json_equal(msg->id, request_id)) {
    1514                 :          8 :             print_json(msg->result);
    1515                 :          8 :             putchar('\n');
    1516                 :          8 :             fflush(stdout);
    1517                 :          8 :             enable_lock_request = true;
    1518                 :          8 :             json_destroy(request_id);
    1519                 :          8 :             request_id = NULL;
    1520                 :          8 :             daemonize_complete();
    1521         [ +  - ]:          3 :         } else if (msg->type == JSONRPC_NOTIFY) {
    1522                 :          3 :             puts(msg->method);
    1523                 :          3 :             print_json(msg->params);
    1524                 :          3 :             putchar('\n');
    1525                 :          3 :             fflush(stdout);
    1526                 :            :         }
    1527                 :            : 
    1528                 :         11 :         jsonrpc_msg_destroy(msg);
    1529                 :            : 
    1530                 :            : no_msg:
    1531         [ -  + ]:         29 :         if (exiting) {
    1532                 :          0 :             break;
    1533                 :            :         }
    1534                 :            : 
    1535                 :         29 :         jsonrpc_run(rpc);
    1536                 :         29 :         jsonrpc_wait(rpc);
    1537                 :         29 :         jsonrpc_recv_wait(rpc);
    1538                 :            : 
    1539                 :         29 :         unixctl_server_wait(unixctl);
    1540                 :         29 :         poll_block();
    1541                 :         29 :     }
    1542                 :            : 
    1543                 :          0 :     json_destroy(request_id);
    1544                 :          0 :     unixctl_server_destroy(unixctl);
    1545                 :          0 : }
    1546                 :            : 
    1547                 :            : static void
    1548                 :          5 : do_lock_create(struct jsonrpc *rpc, const char *database OVS_UNUSED,
    1549                 :            :                int argc OVS_UNUSED, char *argv[])
    1550                 :            : {
    1551                 :          5 :     do_lock(rpc, "lock", argv[0]);
    1552                 :          0 : }
    1553                 :            : 
    1554                 :            : static void
    1555                 :          1 : do_lock_steal(struct jsonrpc *rpc, const char *database OVS_UNUSED,
    1556                 :            :               int argc OVS_UNUSED, char *argv[])
    1557                 :            : {
    1558                 :          1 :     do_lock(rpc, "steal", argv[0]);
    1559                 :          0 : }
    1560                 :            : 
    1561                 :            : static void
    1562                 :          0 : do_lock_unlock(struct jsonrpc *rpc, const char *database OVS_UNUSED,
    1563                 :            :                int argc OVS_UNUSED, char *argv[])
    1564                 :            : {
    1565                 :          0 :     do_lock(rpc, "unlock", argv[0]);
    1566                 :          0 : }
    1567                 :            : 
    1568                 :            : /* All command handlers (except for "help") are expected to take an optional
    1569                 :            :  * server socket name (e.g. "unix:...") as their first argument.  The socket
    1570                 :            :  * name argument must be included in max_args (but left out of min_args).  The
    1571                 :            :  * command name and socket name are not included in the arguments passed to the
    1572                 :            :  * handler: the argv[0] passed to the handler is the first argument after the
    1573                 :            :  * optional server socket name.  The connection to the server is available as
    1574                 :            :  * global variable 'rpc'. */
    1575                 :            : static const struct ovsdb_client_command all_commands[] = {
    1576                 :            :     { "list-dbs",           NEED_RPC,      0, 0,       do_list_dbs },
    1577                 :            :     { "get-schema",         NEED_DATABASE, 0, 0,       do_get_schema },
    1578                 :            :     { "get-schema-version", NEED_DATABASE, 0, 0,       do_get_schema_version },
    1579                 :            :     { "list-tables",        NEED_DATABASE, 0, 0,       do_list_tables },
    1580                 :            :     { "list-columns",       NEED_DATABASE, 0, 1,       do_list_columns },
    1581                 :            :     { "transact",           NEED_RPC,      1, 1,       do_transact },
    1582                 :            :     { "monitor",            NEED_DATABASE, 1, INT_MAX, do_monitor },
    1583                 :            :     { "monitor-cond",       NEED_DATABASE, 2, 3,       do_monitor_cond },
    1584                 :            :     { "dump",               NEED_DATABASE, 0, INT_MAX, do_dump },
    1585                 :            :     { "lock",               NEED_RPC,      1, 1,       do_lock_create },
    1586                 :            :     { "steal",              NEED_RPC,      1, 1,       do_lock_steal },
    1587                 :            :     { "unlock",             NEED_RPC,      1, 1,       do_lock_unlock },
    1588                 :            :     { "help",               NEED_NONE,     0, INT_MAX, do_help },
    1589                 :            : 
    1590                 :            :     { NULL,                 0,             0, 0,       NULL },
    1591                 :            : };
    1592                 :            : 
    1593                 :        906 : static const struct ovsdb_client_command *get_all_commands(void)
    1594                 :            : {
    1595                 :        906 :     return all_commands;
    1596                 :            : }

Generated by: LCOV version 1.12