1 // Copyright 2020 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /// Very crude interactive console to allow the test host to run shell commands
6 /// in the guest and receive the output.
7 mod wire_format;
8
9 use std::fs::File;
10 use std::io;
11 use std::io::prelude::*;
12 #[cfg(any(target_os = "android", target_os = "linux"))]
13 use std::os::unix::process::ExitStatusExt;
14 use std::path::Path;
15 use std::process::Command;
16 use std::str;
17
18 use serde_json::Deserializer;
19
20 use crate::wire_format::DelegateMessage;
21 use crate::wire_format::GuestToHostMessage;
22 use crate::wire_format::HostToGuestMessage;
23 use crate::wire_format::ProgramExit;
24
25 /// Device file to read from and write to.
26 const CONSOLE_FILE: &str = "/dev/ttyS1";
27
listen( input: &mut dyn Iterator<Item = Result<DelegateMessage, serde_json::Error>>, mut output: Box<dyn io::Write>, ) -> io::Result<()>28 fn listen(
29 input: &mut dyn Iterator<Item = Result<DelegateMessage, serde_json::Error>>,
30 mut output: Box<dyn io::Write>,
31 ) -> io::Result<()> {
32 output.write_all(
33 serde_json::to_string_pretty(&DelegateMessage::GuestToHost(GuestToHostMessage::Ready))
34 .unwrap()
35 .as_bytes(),
36 )?;
37 loop {
38 if let Some(command) = input.next() {
39 match command?.assume_host_to_guest() {
40 HostToGuestMessage::Exit => {
41 break;
42 }
43 HostToGuestMessage::RunCommand {
44 command: command_string,
45 } => {
46 println!("-> {}", &command_string);
47 let result = Command::new("/bin/sh")
48 .args(["-c", &command_string])
49 .output()
50 .unwrap();
51 let command_result = GuestToHostMessage::ProgramExit(ProgramExit {
52 stdout: String::from_utf8_lossy(&result.stdout).into_owned(),
53 stderr: String::from_utf8_lossy(&result.stderr).into_owned(),
54 exit_status: match result.status.code() {
55 Some(code) => wire_format::ExitStatus::Code(code),
56 #[cfg(any(target_os = "android", target_os = "linux"))]
57 None => match result.status.signal() {
58 Some(signal) => wire_format::ExitStatus::Signal(signal),
59 None => wire_format::ExitStatus::None,
60 },
61 #[cfg(not(unix))]
62 _ => wire_format::ExitStatus::None,
63 },
64 });
65 println!(
66 "<- {}",
67 serde_json::to_string_pretty(&command_result).unwrap()
68 );
69 output.write_all(
70 serde_json::to_string_pretty(&DelegateMessage::GuestToHost(command_result))
71 .unwrap()
72 .as_bytes(),
73 )?;
74 }
75 }
76 }
77 }
78 Ok(())
79 }
80
main()81 fn main() {
82 let path = Path::new(CONSOLE_FILE);
83
84 let mut command_stream =
85 Deserializer::from_reader(File::open(path).unwrap()).into_iter::<DelegateMessage>();
86
87 listen(&mut command_stream, Box::new(File::create(path).unwrap())).unwrap();
88 }
89