• 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 use std::fs::File;
8 use std::io;
9 use std::io::prelude::*;
10 use std::os::unix::process::ExitStatusExt;
11 use std::path::Path;
12 use std::process::Command;
13 use std::process::Stdio;
14 use std::str;
15 
16 /// Device file to read from and write to.
17 const CONSOLE_FILE: &'static str = "/dev/ttyS1";
18 
19 /// Line sent when we are ready to receive a command.
20 /// \x05 is the ENQ (enquiry) character, which is rarely used and 'should'
21 /// not appear in command output.
22 const READY_LINE: &'static str = "\x05READY";
23 
24 /// Line sent containing the exit code of the program
25 /// \x05 is the ENQ (enquiry) character, which is rarely used and 'should'
26 /// not appear in command output.
27 const EXIT_CODE_LINE: &'static str = "\x05EXIT_CODE";
28 
29 /// When ready to receive a command, the `READY_LINE` is written to `input`.
30 /// The received command is executed via /bin/sh and it's stdout is written
31 /// back to `output`, terminated by `EXIT_CODE_LINE ${exit_code}`.
listen(input: Box<dyn io::Read>, mut output: Box<dyn io::Write>) -> io::Result<()>32 fn listen(input: Box<dyn io::Read>, mut output: Box<dyn io::Write>) -> io::Result<()> {
33     let mut reader = io::BufReader::new(input);
34     loop {
35         writeln!(&mut output, "{}", READY_LINE).unwrap();
36 
37         let mut command = String::new();
38         reader.read_line(&mut command)?;
39         if command.trim() == "exit" {
40             break;
41         }
42 
43         println!("-> {:?}", command);
44         let result = Command::new("/bin/sh")
45             .args(&["-c", &command])
46             .stderr(Stdio::inherit())
47             .output()
48             .unwrap();
49         let exit_code = match result.status.code() {
50             Some(code) => code,
51             None => -result.status.signal().unwrap(),
52         };
53 
54         output.write(&result.stdout)?;
55         println!("<- {}", exit_code);
56         writeln!(&mut output, "{EXIT_CODE_LINE} {exit_code}")?;
57     }
58     Ok(())
59 }
60 
main()61 fn main() {
62     let path = Path::new(CONSOLE_FILE);
63     listen(
64         Box::new(File::open(path).unwrap()),
65         Box::new(File::create(path).unwrap()),
66     )
67     .unwrap();
68 }
69