+static void
+query_db_remotes(const char *name_, const struct ovsdb *db,
+ struct shash *remotes)
+{
+ char *name, *db_prefix, *table_name, *column_name;
+ const struct ovsdb_column *column;
+ const struct ovsdb_table *table;
+ const struct ovsdb_row *row;
+ char *save_ptr = NULL;
+
+ name = xstrdup(name_);
+ db_prefix = strtok_r(name, ":", &save_ptr);
+ table_name = strtok_r(NULL, ",", &save_ptr);
+ column_name = strtok_r(NULL, ",", &save_ptr);
+ if (!table_name || !column_name) {
+ ovs_fatal(0, "remote \"%s\": invalid syntax", name_);
+ }
+
+ table = ovsdb_get_table(db, table_name);
+ if (!table) {
+ ovs_fatal(0, "remote \"%s\": no table named %s", name_, table_name);
+ }
+
+ column = ovsdb_table_schema_get_column(table->schema, column_name);
+ if (!column) {
+ ovs_fatal(0, "remote \"%s\": table \"%s\" has no column \"%s\"",
+ name_, table_name, column_name);
+ }
+
+ if (column->type.key_type != OVSDB_TYPE_STRING
+ || column->type.value_type != OVSDB_TYPE_VOID) {
+ ovs_fatal(0, "remote \"%s\": type of table \"%s\" column \"%s\" is "
+ "not string or set of strings",
+ name_, table_name, column_name);
+ }
+
+ HMAP_FOR_EACH (row, struct ovsdb_row, hmap_node, &table->rows) {
+ const struct ovsdb_datum *datum;
+ size_t i;
+
+ datum = &row->fields[column->index];
+ for (i = 0; i < datum->n; i++) {
+ shash_add_once(remotes, datum->keys[i].string, NULL);
+ }
+ }
+
+ free(name);
+}
+
+static void
+set_remotes(struct ovsdb_jsonrpc_server *jsonrpc,
+ const struct ovsdb *db, struct shash *remotes)
+{
+ struct shash resolved_remotes;
+ struct shash_node *node;
+
+ shash_init(&resolved_remotes);
+ SHASH_FOR_EACH (node, remotes) {
+ const char *name = node->name;
+
+ if (!strncmp(name, "db:", 3)) {
+ query_db_remotes(name, db, &resolved_remotes);
+ } else {
+ shash_add_once(&resolved_remotes, name, NULL);
+ }
+ }
+ ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes);
+ shash_destroy(&resolved_remotes);
+}
+
+
+static void
+ovsdb_server_exit(struct unixctl_conn *conn, const char *args UNUSED,
+ void *exiting_)
+{
+ bool *exiting = exiting_;
+ *exiting = true;
+ unixctl_command_reply(conn, 200, NULL);
+}
+