Skip to content

Commit 26a295d

Browse files
committed
virtio-console: Implement redirection for stdin/stdout/stderr
TODO: implement stderr here too! This is done by creating a port for each of stdin/stdout/stderr, Each of these ports is multidirectional but we only use one direction. Port 0 must always be a console - this is implied by the specification. Signed-off-by: Matej Hrica <[email protected]>
1 parent 104ff72 commit 26a295d

File tree

17 files changed

+891
-293
lines changed

17 files changed

+891
-293
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

init/init.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,68 @@ void clock_worker()
756756
}
757757
#endif
758758

759+
int reopen_fd(int fd, char *path, int flags)
760+
{
761+
int newfd = open(path,flags);
762+
if (newfd < 0) {
763+
printf("Failed to open '%s': %s\n", path,strerror(errno));
764+
return -1;
765+
}
766+
767+
close(fd);
768+
if (dup2(newfd, fd) < 0) {
769+
perror("dup2");
770+
close(newfd);
771+
return -1;
772+
}
773+
close(newfd);
774+
return 0;
775+
}
776+
777+
int setup_redirects()
778+
{
779+
DIR *ports_dir = opendir("/sys/class/virtio-ports");
780+
if (ports_dir == NULL) {
781+
printf("Unable to open ports directory!\n");
782+
return -4;
783+
}
784+
785+
char path[2048];
786+
char name_buf[1024];
787+
788+
struct dirent *entry = NULL;
789+
while ((entry=readdir(ports_dir))) {
790+
char* port_identifier = entry->d_name;
791+
int result_len = snprintf(path, sizeof(path), "/sys/class/virtio-ports/%s/name", port_identifier);
792+
793+
// result was truncated
794+
if (result_len > sizeof(name_buf) - 1) {
795+
printf("Path buffer too small");
796+
return -1;
797+
}
798+
799+
FILE *port_name_file = fopen(path, "r");
800+
if (port_name_file == NULL) {
801+
continue;
802+
}
803+
804+
char *port_name = fgets(name_buf, sizeof(name_buf), port_name_file);
805+
fclose(port_name_file);
806+
807+
if (port_name != NULL && strcmp(port_name, "krun-stdin\n") == 0) {
808+
// if previous snprintf didn't fail, this one cannot fail either
809+
snprintf(path, sizeof(path), "/dev/%s", port_identifier);
810+
reopen_fd(STDIN_FILENO, path, O_RDONLY);
811+
}else if (port_name != NULL && strcmp(port_name, "krun-stdout\n") == 0) {
812+
snprintf(path, sizeof(path), "/dev/%s", port_identifier);
813+
reopen_fd(STDOUT_FILENO, path, O_WRONLY);
814+
}
815+
}
816+
817+
closedir(ports_dir);
818+
return 0;
819+
}
820+
759821
int main(int argc, char **argv)
760822
{
761823
struct ifreq ifr;
@@ -848,6 +910,10 @@ int main(int argc, char **argv)
848910
}
849911
#endif
850912

913+
if (setup_redirects() < 0) {
914+
exit(-4);
915+
}
916+
851917
if (execvp(exec_argv[0], exec_argv) < 0) {
852918
printf("Couldn't execute '%s' inside the vm: %s\n", exec_argv[0], strerror(errno));
853919
exit(-3);

src/devices/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ crossbeam-channel = "0.5"
1515
env_logger = "0.9.0"
1616
libc = ">=0.2.39"
1717
log = "0.4.0"
18-
nix = "0.24.1"
18+
nix = { version = "0.24.1", features = ["poll"] }
1919
rand = "0.8.5"
2020
vm-memory = { version = ">=0.13", features = ["backend-mmap"] }
2121

src/devices/src/virtio/console/console_control.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use utils::eventfd::EventFd;
77
use vm_memory::{ByteValued, GuestMemoryMmap};
88

99
use crate::virtio::console::defs::control_event::{
10-
VIRTIO_CONSOLE_CONSOLE_PORT, VIRTIO_CONSOLE_PORT_ADD, VIRTIO_CONSOLE_RESIZE,
10+
VIRTIO_CONSOLE_CONSOLE_PORT, VIRTIO_CONSOLE_PORT_ADD, VIRTIO_CONSOLE_PORT_NAME,
11+
VIRTIO_CONSOLE_PORT_OPEN, VIRTIO_CONSOLE_RESIZE,
1112
};
1213

1314
#[derive(Copy, Clone, Debug, Default)]
@@ -99,6 +100,31 @@ impl ConsoleControl {
99100
})
100101
}
101102

103+
pub fn port_open(&self, port_id: u32, open: bool) {
104+
self.push_msg(VirtioConsoleControl {
105+
id: port_id,
106+
event: VIRTIO_CONSOLE_PORT_OPEN,
107+
value: open as u16,
108+
})
109+
}
110+
111+
pub fn port_name(&self, port_id: u32, name: &str) {
112+
let mut buf: Vec<u8> = Vec::new();
113+
114+
buf.extend_from_slice(
115+
VirtioConsoleControl {
116+
id: port_id,
117+
event: VIRTIO_CONSOLE_PORT_NAME,
118+
value: 1, // Unspecified/unused in the spec, lets use the same value as QEMU.
119+
}
120+
.as_slice(),
121+
);
122+
123+
// The spec says the name shouldn't be NUL terminated.
124+
buf.extend(name.as_bytes());
125+
self.push_vec(buf)
126+
}
127+
102128
pub fn queue_pop(&self) -> Option<Payload> {
103129
let mut queue = self.queue.lock().expect("Poisoned lock");
104130
queue.pop_front()

0 commit comments

Comments
 (0)