summary refs log tree commit diff
diff options
context:
space:
mode:
authorJorge E. Moreira <jemoreira@google.com>2019-08-01 14:40:03 -0700
committerCommit Bot <commit-bot@chromium.org>2019-08-03 20:03:23 +0000
commit1e26230f3a490a7955d2ea9fe7855af5498ced70 (patch)
treede59ab5928eac607c33bd4de6289bb230f2f6c51
parent54e660ba8b912cf9c1fe7837cd42d21b9cfe9133 (diff)
downloadcrosvm-1e26230f3a490a7955d2ea9fe7855af5498ced70.tar
crosvm-1e26230f3a490a7955d2ea9fe7855af5498ced70.tar.gz
crosvm-1e26230f3a490a7955d2ea9fe7855af5498ced70.tar.bz2
crosvm-1e26230f3a490a7955d2ea9fe7855af5498ced70.tar.lz
crosvm-1e26230f3a490a7955d2ea9fe7855af5498ced70.tar.xz
crosvm-1e26230f3a490a7955d2ea9fe7855af5498ced70.tar.zst
crosvm-1e26230f3a490a7955d2ea9fe7855af5498ced70.zip
Allow to connect standard input to a serial port other than the guest console
Before this change, setting console=true on a serial port caused that
port to be the one connected to the crosvm process' standard input. By
adding an extra 'stdin' argument to the serial parameters it's
possible to make those concepts independent.
Just as with the console argument, stdin defaults to serial port
1 (ttyS0) when not provided and it's possible to set no serial port
connected to stdin (or set as the console) by defining the first
serial port without the stdin (console) argument.

BUG=b/138616941
TEST=boot debian guest in debian host, boot cuttlefish in debian host
Change-Id: I7273e6860218521073df93a4ad71e31c7da522a5
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1731139
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Auto-Submit: Jorge Moreira Broche <jemoreira@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Zach Reizner <zachr@chromium.org>
-rw-r--r--arch/src/lib.rs3
-rw-r--r--devices/src/serial.rs5
-rw-r--r--src/main.rs30
3 files changed, 36 insertions, 2 deletions
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 71e4327..28f1168 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -271,6 +271,9 @@ pub fn add_serial_devices(
 
         if param.console {
             stdio_serial_num = Some(x + 1);
+        }
+
+        if param.stdin {
             stdio_serial = Some(com.clone());
         }
     }
diff --git a/devices/src/serial.rs b/devices/src/serial.rs
index 0bf5642..5ecefd7 100644
--- a/devices/src/serial.rs
+++ b/devices/src/serial.rs
@@ -127,6 +127,7 @@ pub struct SerialParameters {
     pub path: Option<PathBuf>,
     pub num: u8,
     pub console: bool,
+    pub stdin: bool,
 }
 
 impl SerialParameters {
@@ -169,24 +170,28 @@ pub const DEFAULT_SERIAL_PARAMS: [SerialParameters; 4] = [
         path: None,
         num: 1,
         console: true,
+        stdin: true,
     },
     SerialParameters {
         type_: SerialType::Sink,
         path: None,
         num: 2,
         console: false,
+        stdin: false,
     },
     SerialParameters {
         type_: SerialType::Sink,
         path: None,
         num: 3,
         console: false,
+        stdin: false,
     },
     SerialParameters {
         type_: SerialType::Sink,
         path: None,
         num: 4,
         console: false,
+        stdin: false,
     },
 ];
 
diff --git a/src/main.rs b/src/main.rs
index 81f20a7..78dfbf2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -251,6 +251,7 @@ fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> {
         path: None,
         num: 1,
         console: false,
+        stdin: false,
     };
 
     let opts = s
@@ -285,6 +286,11 @@ fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> {
                     ))
                 })?
             }
+            "stdin" => {
+                serial_setting.stdin = v.parse::<bool>().map_err(|e| {
+                    argument::Error::Syntax(format!("serial device stdin is not parseable: {}", e))
+                })?
+            }
             "path" => serial_setting.path = Some(PathBuf::from(v)),
             _ => {
                 return Err(argument::Error::UnknownArgument(format!(
@@ -409,6 +415,15 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
                 }
             }
 
+            if serial_params.stdin {
+                if let Some(previous_stdin) = cfg.serial_parameters.values().find(|sp| sp.stdin) {
+                    return Err(argument::Error::TooManyArguments(format!(
+                        "serial device {} already connected to standard input",
+                        previous_stdin.num
+                    )));
+                }
+            }
+
             cfg.serial_parameters.insert(num, serial_params);
         }
         "syslog-tag" => {
@@ -840,13 +855,14 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
           Argument::flag("cras-capture", "Enable capturing audio from CRAS server to the cras-audio device"),
           Argument::flag("null-audio", "Add an audio device to the VM that plays samples to /dev/null"),
           Argument::value("serial",
-                          "type=TYPE,[num=NUM,path=PATH,console]",
+                          "type=TYPE,[num=NUM,path=PATH,console,stdin]",
                           "Comma seperated key=value pairs for setting up serial devices. Can be given more than once.
                           Possible key values:
                           type=(stdout,syslog,sink,file) - Where to route the serial device
                           num=(1,2,3,4) - Serial Device Number. If not provided, num will default to 1.
                           path=PATH - The path to the file to write to when type=file
                           console - Use this serial device as the guest console. Can only be given once. Will default to first serial port if not provided.
+                          stdin - Direct standard input to this serial device. Can only be given once. Will default to first serial port if not provided.
                           "),
           Argument::value("syslog-tag", "TAG", "When logging to syslog, use the provided tag."),
           Argument::value("wayland-sock", "PATH", "Path to the Wayland socket to use."),
@@ -1423,7 +1439,8 @@ mod tests {
 
     #[test]
     fn parse_serial_vaild() {
-        parse_serial_options("type=syslog,num=1,console=true").expect("parse should have succeded");
+        parse_serial_options("type=syslog,num=1,console=true,stdin=true")
+            .expect("parse should have succeded");
     }
 
     #[test]
@@ -1455,4 +1472,13 @@ mod tests {
     fn parse_serial_invalid_option() {
         parse_serial_options("type=syslog,speed=lightspeed").expect_err("parse should have failed");
     }
+
+    #[test]
+    fn parse_serial_invalid_two_stdin() {
+        let mut config = Config::default();
+        set_argument(&mut config, "serial", Some("num=1,type=stdout,stdin=true"))
+            .expect("should parse the first serial argument");
+        set_argument(&mut config, "serial", Some("num=2,type=stdout,stdin=true"))
+            .expect_err("should fail to parse a second serial port connected to stdin");
+    }
 }