| // 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 port) |
| : socket_endpoint_(socket_endpoint.BindSync()), port_(port) {} |
| |
| fpromise::result<vsh::BlockingCommandRunner::CommandResult, zx_status_t> |
| BlockingCommandRunner::Execute(Command command) { |
| auto client_result = BlockingClient::Connect(socket_endpoint_, port_); |
| if (client_result.is_error()) { |
| return fpromise::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 fpromise::error(status); |
| } |
| |
| std::string out; |
| std::string err; |
| int32_t return_code; |
| while (client.status() == vm_tools::vsh::ConnectionStatus::READY) { |
| fpromise::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 fpromise::error(ZX_ERR_CONNECTION_RESET); |
| } break; |
| default: { |
| FX_LOGS(ERROR) << "Invalid state change to " << new_status; |
| return fpromise::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 fpromise::error(ZX_ERR_NOT_SUPPORTED); |
| } break; |
| } |
| } break; |
| default: { |
| FX_LOGS(ERROR) << "Unsupported message type " << message.msg_case(); |
| return fpromise::error(ZX_ERR_NOT_SUPPORTED); |
| } break; |
| } |
| } |
| |
| return fpromise::ok(vsh::BlockingCommandRunner::CommandResult{ |
| out, |
| err, |
| return_code, |
| }); |
| } |
| |
| } // namespace vsh |