| // Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/virtualization/lib/vsh/command_runner.h" | |
| #include <lib/syslog/cpp/macros.h> | |
| #include "src/virtualization/lib/vsh/client.h" | |
| namespace vsh { | |
| BlockingCommandRunner::BlockingCommandRunner( | |
| fidl::InterfaceHandle<fuchsia::virtualization::HostVsockEndpoint> socket_endpoint, uint32_t cid, | |
| uint32_t port) | |
| : socket_endpoint_(socket_endpoint.BindSync()), cid_(cid), port_(port) {} | |
| fit::result<vsh::BlockingCommandRunner::CommandResult, zx_status_t> BlockingCommandRunner::Execute( | |
| Command command) { | |
| auto client_result = BlockingClient::Connect(socket_endpoint_, cid_, port_); | |
| if (client_result.is_error()) { | |
| return fit::error(client_result.error()); | |
| } | |
| auto client = client_result.take_value(); | |
| vm_tools::vsh::SetupConnectionRequest setup_request; | |
| setup_request.set_nopty(true); | |
| setup_request.mutable_env()->insert(command.env.begin(), command.env.end()); | |
| for (auto& arg : command.argv) { | |
| setup_request.add_argv(std::move(arg)); | |
| } | |
| zx_status_t status = client.Setup(std::move(setup_request)); | |
| if (status != ZX_OK) { | |
| return fit::error(status); | |
| } | |
| std::string out; | |
| std::string err; | |
| int32_t return_code; | |
| while (client.status() == vm_tools::vsh::ConnectionStatus::READY) { | |
| fit::result<vm_tools::vsh::HostMessage, zx_status_t> message_result = client.NextMessage(); | |
| if (message_result.is_error()) { | |
| break; | |
| } | |
| auto message = message_result.take_value(); | |
| switch (message.msg_case()) { | |
| case vm_tools::vsh::HostMessage::MsgCase::kStatusMessage: { | |
| auto new_status = message.status_message().status(); | |
| switch (new_status) { | |
| case vm_tools::vsh::ConnectionStatus::EXITED: { | |
| return_code = message.status_message().code(); | |
| } break; | |
| case vm_tools::vsh::ConnectionStatus::FAILED: { | |
| FX_LOGS(ERROR) << "Fatal error: " << message.status_message().description(); | |
| return fit::error(ZX_ERR_CONNECTION_RESET); | |
| } break; | |
| default: { | |
| FX_LOGS(ERROR) << "Invalid state change to " << new_status; | |
| return fit::error(ZX_ERR_INVALID_ARGS); | |
| } break; | |
| } | |
| } break; | |
| case vm_tools::vsh::HostMessage::MsgCase::kDataMessage: { | |
| auto data = message.data_message(); | |
| switch (data.stream()) { | |
| case vm_tools::vsh::StdioStream::STDOUT_STREAM: { | |
| out.append(data.data()); | |
| } break; | |
| case vm_tools::vsh::StdioStream::STDERR_STREAM: { | |
| err.append(data.data()); | |
| } break; | |
| default: { | |
| FX_LOGS(ERROR) << "Unsupported STDIO stream " << data.stream(); | |
| return fit::error(ZX_ERR_NOT_SUPPORTED); | |
| } break; | |
| } | |
| } break; | |
| default: { | |
| FX_LOGS(ERROR) << "Unsupported message type " << message.msg_case(); | |
| return fit::error(ZX_ERR_NOT_SUPPORTED); | |
| } break; | |
| } | |
| } | |
| return fit::ok(vsh::BlockingCommandRunner::CommandResult{ | |
| out, | |
| err, | |
| return_code, | |
| }); | |
| } | |
| } // namespace vsh |