• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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