| 286 | } |
| 287 | |
| 288 | int Client::AttachConsole(const std::string& vm_id) const { |
| 289 | auto conn = ipc::UnixSocketClient::Connect(socket_path_); |
| 290 | if (!conn.IsValid()) { |
| 291 | std::cerr << "failed to connect to " << socket_path_ << "\n"; |
| 292 | return 1; |
| 293 | } |
| 294 | |
| 295 | if (!WriteJsonLine(conn, {{"type", "vm.console.attach"}, {"vm_id", vm_id}})) { |
| 296 | std::cerr << "failed to send console attach request\n"; |
| 297 | return 1; |
| 298 | } |
| 299 | |
| 300 | std::string first = conn.ReadLine(); |
| 301 | auto response = nlohmann::json::parse(first, nullptr, false); |
| 302 | if (response.is_discarded() || !response.value("ok", false)) { |
| 303 | std::cerr << (response.is_object() ? response.value("error", "console attach failed") |
| 304 | : "console attach failed") |
| 305 | << "\n"; |
| 306 | return 1; |
| 307 | } |
| 308 | |
| 309 | std::cerr << "Attached to " << vm_id << ". Press Ctrl-] to detach.\n"; |
| 310 | RawTerminal raw; |
| 311 | |
| 312 | while (true) { |
| 313 | while (conn.HasBufferedLine()) { |
| 314 | auto event = nlohmann::json::parse(conn.ReadLine(), nullptr, false); |
| 315 | if (!event.is_discarded()) { |
| 316 | if (event.value("type", "") == "console.closed") { |
| 317 | PrintDetached(raw); |
| 318 | return 0; |
| 319 | } |
| 320 | HandleConsoleEvent(event); |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | pollfd fds[2] = { |
| 325 | {.fd = STDIN_FILENO, .events = POLLIN, .revents = 0}, |
| 326 | {.fd = conn.fd(), .events = POLLIN, .revents = 0}, |
| 327 | }; |
| 328 | const int rc = ::poll(fds, 2, -1); |
| 329 | if (rc <= 0) continue; |
| 330 | |
| 331 | if (fds[0].revents & POLLIN) { |
| 332 | char buf[4096]; |
| 333 | const ssize_t n = ::read(STDIN_FILENO, buf, sizeof(buf)); |
| 334 | if (n <= 0) break; |
| 335 | if (n == 1 && buf[0] == 0x1d) break; // Ctrl-] |
| 336 | const std::string input = StripHostTerminalResponses(buf, static_cast<size_t>(n)); |
| 337 | if (input.empty()) continue; |
| 338 | if (!WriteJsonLine(conn, { |
| 339 | {"type", "console.input"}, |
| 340 | {"vm_id", vm_id}, |
| 341 | {"data_hex", BytesToHex(input.data(), input.size())}, |
| 342 | })) { |
| 343 | break; |
| 344 | } |
| 345 | } |
no test coverage detected