Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lib/virtual-fs/src/host_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,10 @@ impl VirtualFile for File {
None
}

fn is_terminal(&self) -> bool {
std::io::IsTerminal::is_terminal(&self.inner_std)
}

fn poll_read_ready(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
let cursor = match self.inner_std.stream_position() {
Ok(a) => a,
Expand Down Expand Up @@ -616,6 +620,10 @@ impl VirtualFile for Stdout {
Some(1)
}

fn is_terminal(&self) -> bool {
std::io::IsTerminal::is_terminal(&std::io::stdout())
}

fn poll_read_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
Poll::Ready(Ok(0))
}
Expand Down Expand Up @@ -790,6 +798,10 @@ impl VirtualFile for Stderr {
Some(2)
}

fn is_terminal(&self) -> bool {
std::io::IsTerminal::is_terminal(&std::io::stderr())
}

fn poll_read_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
Poll::Ready(Ok(0))
}
Expand Down Expand Up @@ -905,6 +917,11 @@ impl VirtualFile for Stdin {
fn get_special_fd(&self) -> Option<u32> {
Some(0)
}

fn is_terminal(&self) -> bool {
std::io::IsTerminal::is_terminal(&std::io::stdin())
}

fn poll_read_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
{
let read_buffer = self.read_buffer.lock().unwrap();
Expand Down
8 changes: 8 additions & 0 deletions lib/virtual-fs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,14 @@ pub trait VirtualFile:
None
}

/// Indicates whether this file is connected to a terminal.
///
/// Virtual files are not terminals by default. Implementations that wrap
/// host standard streams may override this to report the host TTY state.
fn is_terminal(&self) -> bool {
false
}

/// Writes to this file using an mmap offset and reference
/// (this method only works for mmap optimized file systems)
fn write_from_mmap(&mut self, _offset: u64, _len: u64) -> std::io::Result<()> {
Expand Down
87 changes: 83 additions & 4 deletions lib/wasix/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1838,27 +1838,41 @@ impl WasiFs {
Ok(*guard.deref())
}

fn std_fd_filetype(is_tty: bool) -> Filetype {
if is_tty {
Filetype::CharacterDevice
} else {
Filetype::Unknown
}
}

fn std_fd_is_terminal(&self, fd: WasiFd) -> bool {
WasiInodes::std_dev_get(&self.fd_map, fd)
.map(|file| file.is_terminal())
.unwrap_or(false)
}

pub fn fdstat(&self, fd: WasiFd) -> Result<Fdstat, Errno> {
match fd {
__WASI_STDIN_FILENO => {
return Ok(Fdstat {
fs_filetype: Filetype::CharacterDevice,
fs_filetype: Self::std_fd_filetype(self.std_fd_is_terminal(fd)),
fs_flags: Fdflags::empty(),
fs_rights_base: STDIN_DEFAULT_RIGHTS,
fs_rights_inheriting: Rights::empty(),
});
}
__WASI_STDOUT_FILENO => {
return Ok(Fdstat {
fs_filetype: Filetype::CharacterDevice,
fs_filetype: Self::std_fd_filetype(self.std_fd_is_terminal(fd)),
fs_flags: Fdflags::APPEND,
fs_rights_base: STDOUT_DEFAULT_RIGHTS,
fs_rights_inheriting: Rights::empty(),
});
}
__WASI_STDERR_FILENO => {
return Ok(Fdstat {
fs_filetype: Filetype::CharacterDevice,
fs_filetype: Self::std_fd_filetype(self.std_fd_is_terminal(fd)),
fs_flags: Fdflags::APPEND,
fs_rights_base: STDERR_DEFAULT_RIGHTS,
fs_rights_inheriting: Rights::empty(),
Expand Down Expand Up @@ -2899,13 +2913,78 @@ mod tests {
use super::*;
use once_cell::sync::OnceCell;
use tempfile::tempdir;
use virtual_fs::{RootFileSystemBuilder, TmpFileSystem};
use virtual_fs::{NullFile, RootFileSystemBuilder, TmpFileSystem};
use wasmer::Engine;
use wasmer_config::package::PackageId;

use crate::WasiEnvBuilder;
use crate::bin_factory::{BinaryPackage, BinaryPackageMount, BinaryPackageMounts};

#[tokio::test]
async fn fdstat_uses_swapped_stdio_terminal_state() {
let inodes = WasiInodes::new();
let fs_backing =
WasiFsRoot::from_filesystem(Arc::new(RootFileSystemBuilder::default().build_tmp()));
let wasi_fs = WasiFs::new_init(fs_backing, &inodes, FS_ROOT_INO).unwrap();

for fd in [
__WASI_STDIN_FILENO,
__WASI_STDOUT_FILENO,
__WASI_STDERR_FILENO,
] {
wasi_fs.swap_file(fd, Box::<NullFile>::default()).unwrap();
assert_eq!(wasi_fs.fdstat(fd).unwrap().fs_filetype, Filetype::Unknown);
}
}

#[cfg(all(unix, feature = "host-fs"))]
#[tokio::test]
async fn fdstat_reports_a_swapped_pty_as_a_terminal() {
use std::{
io::IsTerminal,
os::fd::{FromRawFd, RawFd},
};

let mut master: RawFd = -1;
let mut slave: RawFd = -1;
assert_eq!(
unsafe {
libc::openpty(
&mut master,
&mut slave,
std::ptr::null_mut(),
std::ptr::null(),
std::ptr::null(),
)
},
0
);

let _master = unsafe { std::fs::File::from_raw_fd(master) };
let slave = unsafe { std::fs::File::from_raw_fd(slave) };
assert!(slave.is_terminal());
let inodes = WasiInodes::new();
let fs_backing =
WasiFsRoot::from_filesystem(Arc::new(RootFileSystemBuilder::default().build_tmp()));
let wasi_fs = WasiFs::new_init(fs_backing, &inodes, FS_ROOT_INO).unwrap();
let pty = virtual_fs::host_fs::File::new(
tokio::runtime::Handle::current(),
slave,
PathBuf::from("/dev/pts/test"),
true,
true,
false,
);

wasi_fs
.swap_file(__WASI_STDIN_FILENO, Box::new(pty))
.unwrap();
assert_eq!(
wasi_fs.fdstat(__WASI_STDIN_FILENO).unwrap().fs_filetype,
Filetype::CharacterDevice
);
}

fn webc_symlink_fs() -> virtual_fs::WebcVolumeFileSystem {
let timestamps = webc::v3::Timestamps::default();
let dir = webc::v3::write::Directory::new(
Expand Down
6 changes: 3 additions & 3 deletions lib/wasix/tests/wasm_tests/wasi_fyi/ported_isatty.stdout
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
stdin: 1
stdout: 1
stderr: 1
stdin: 0

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having to change the wasi_fyi suite is a signal we're doing something wrong, since this test suite was created against the WASIp1 standard rather than our implementation of WASIX.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. The test suite asserts unconditionally that std* should be ttys. In our test-harness this is very likely not the case, so I'd expect this to be changed now.

stdout: 0
stderr: 0
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "hi\nhi2\n",
"stderr": "test.wasm-5.1# bash-dist# bash-dist# exit\ntest.wasm-5.1# test.wasm-5.1# exit\n",
Comment thread
marxin marked this conversation as resolved.
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "arch\nbase32\nbase64\nbaseenc\nbasename\nbash\ncat\nchcon\nchgrp\nchmod\nchown\nchroot\ncksum\ncomm\ncp\ncsplit\ncut\ndate\ndd\ndf\ndircolors\ndirname\ndu\necho\nenv\nexpand\nexpr\nfactor\nfalse\nfmt\nfold\ngroups\nhashsum\nhead\nhostid\nhostname\nid\ninstall\njoin\nkill\nlink\nln\nlogname\nls\nmkdir\nmkfifo\nmknod\nmktemp\nmore\nmv\nnice\nnl\nnohup\nnproc\nnumfmt\nod\npaste\npathchk\npinky\npr\nprintenv\nprintf\nptx\npwd\nreadlink\nrealpath\nrelpath\nrm\nrmdir\nruncon\nseq\nsh\nshred\nshuf\nsleep\nsort\nsplit\nstat\nstdbuf\nsum\nsync\ntac\ntail\ntee\ntest\ntimeout\ntouch\ntr\ntrue\ntruncate\ntsort\ntty\nuname\nunexpand\nuniq\nunlink\nuptime\nusers\nwasmer\nwc\nwho\nwhoami\nyes\n",
"stderr": "test.wasm-5.1# test.wasm-5.1# test.wasm-5.1# exit\n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "hi\n",
"stderr": "test.wasm-5.1# test.wasm-5.1# test.wasm-5.1# exit\n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "hello\n",
"stderr": "test.wasm-5.1# test.wasm-5.1# exit\n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "bin\ndev\netc\ntmp\nusr\n",
"stderr": "test.wasm-5.1# test.wasm-5.1# exit\n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "hello\n",
"stderr": "test.wasm-5.1# test.wasm-5.1# exit\n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "10\n",
"stderr": "test.wasm-5.1# test.wasm-5.1# exit\n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "hi\n",
"stderr": "# bash-dist# exit\n# # ",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "hi\n",
"stderr": "# # # ",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "2\n",
"stderr": "# # \n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "hello\n",
"stderr": "# # \n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ expression: snapshot
"result": {
"Success": {
"stdout": "10\n",
"stderr": "# # \n",
"stderr": "",
"exit_code": 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ expression: snapshot
},
"result": {
"Success": {
"stdout": "EFD_NONBLOCK:4\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\n",
"stdout": "EFD_NONBLOCK:4\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\n",
"stderr": "",
"exit_code": 0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ expression: snapshot
},
"result": {
"Success": {
"stdout": "EFD_NONBLOCK:4\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\n",
"stdout": "EFD_NONBLOCK:4\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess write to efd, write 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\nsuccess read from efd, read 8 bytes(4)\n",
"stderr": "",
"exit_code": 0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ expression: snapshot
},
"result": {
"Success": {
"stdout": "Main program started\nexecve: echo hi-from-child\nhi-from-child\nhi-from-parent\n",
"stdout": "Main program started\nhi-from-child\nhi-from-parent\n",
"stderr": "Child(2) exited with 0\nexecve: echo hi-from-parent\n",
"exit_code": 0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ expression: snapshot
},
"result": {
"Success": {
"stdout": "Main program started\nexecve: echo hi-from-child\nhi-from-child\nhi-from-parent\n",
"stdout": "Main program started\nhi-from-child\nhi-from-parent\n",
"stderr": "Child(2) exited with 0\nexecve: echo hi-from-parent\n",
"exit_code": 0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ expression: snapshot
},
"result": {
"Success": {
"stdout": "Main program started\nexecve: echo hi-from-child\nhi-from-child\nhi-from-parent\n",
"stdout": "Main program started\nhi-from-child\nhi-from-parent\n",
"stderr": "Child(2) exited with 0\nexecve: echo hi-from-parent\n",
"exit_code": 0
}
Expand Down
Loading