Skip to content

Commit

Permalink
qemu: Send guest command output to virtio-serial port
Browse files Browse the repository at this point in the history
This teaches the command entrypoint to locate the virtio-serial port and
stream all output (with stdout and stderr merged) to the chardev. This
gives us streaming command output which is a much nicer UX for the user.

But b/c we support virtual machine images (as well as plain kernel), we
make the virtio-serial port optional. B/c we don't require folks build
VM image kernels with CONFIG_VIRTIO_CONSOLE.
  • Loading branch information
danobi committed Dec 19, 2023
1 parent 8dccb75 commit 0d0ee5e
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/init/command.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,26 @@
cd { host_shared }
{{ endif }}

# Discover where the output chardev is located
vport=
for dir in /sys/class/virtio-ports/*; do
if [[ "$(cat "$dir/name")" == "{ command_output_port_name }" ]]; then
vport_name=$(basename "$dir")
vport="/dev/$vport_name"
fi
done

# Send the rest of the script to the output chardev
if [[ -n "$vport" ]]; then
exec > "$vport"
exec 2>&1
else
# Make a missing serial port a soft error. We don't necessarily need
# streamed command output -- it's completely a UX thing. It's more
# likely this fails on images.
echo >&2 "vmtest: Failed to locate command output virtio-serial port."
echo >&2 "vmtest: Falling back to qemu-guest-agent output capture."
fi

# Run user supplied command
{ command }
3 changes: 3 additions & 0 deletions src/qemu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ struct CommandContext {
host_shared: PathBuf,
/// User supplied command to run
command: String,
/// virtio-serial output port name
command_output_port_name: String,
}

const QEMU_DEFAULT_ARGS: &[&str] = &["-nodefaults", "-display", "none"];
Expand Down Expand Up @@ -721,6 +723,7 @@ impl Qemu {
should_cd: !self.image && self.rootfs == Target::default_rootfs(),
host_shared: self.host_shared.clone(),
command: self.command.clone(),
command_output_port_name: COMMAND_OUTPUT_PORT_NAME.into(),
};

// Same as above, ignore errors cuz only trivial bugs are possible
Expand Down

0 comments on commit 0d0ee5e

Please sign in to comment.