+ /* Allocate a writable empty string since parse_monitor_columns() is
+ * going to strtok() it and that's risky with literal "". */
+ char empty[] = "";
+ json_array_add(
+ monitor_request_array,
+ parse_monitor_columns(empty, server, database, table, &columns));
+ }
+
+ monitor_requests = json_object_create();
+ json_object_put(monitor_requests, table_name, monitor_request_array);
+
+ monitor = json_array_create_3(json_string_create(database),
+ json_null_create(), monitor_requests);
+ request = jsonrpc_create_request("monitor", monitor, NULL);
+ request_id = json_clone(request->id);
+ jsonrpc_send(rpc, request);
+ for (;;) {
+ struct jsonrpc_msg *msg;
+ int error;
+
+ error = jsonrpc_recv_block(rpc, &msg);
+ if (error) {
+ ovsdb_schema_destroy(schema);
+ ovs_fatal(error, "%s: receive failed", server);
+ }
+
+ if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
+ jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
+ msg->id));
+ } else if (msg->type == JSONRPC_REPLY
+ && json_equal(msg->id, request_id)) {
+ monitor_print(msg->result, table, &columns, true);
+ fflush(stdout);
+ if (get_detach()) {
+ /* daemonize() closes the standard file descriptors. We output
+ * to stdout, so we need to save and restore STDOUT_FILENO. */
+ int fd = dup(STDOUT_FILENO);
+ daemonize();
+ dup2(fd, STDOUT_FILENO);
+ close(fd);
+ }
+ } else if (msg->type == JSONRPC_NOTIFY
+ && !strcmp(msg->method, "update")) {
+ struct json *params = msg->params;
+ if (params->type == JSON_ARRAY
+ && params->u.array.n == 2
+ && params->u.array.elems[0]->type == JSON_NULL) {
+ monitor_print(params->u.array.elems[1],
+ table, &columns, false);
+ fflush(stdout);