diff --git a/src/libos/src/fs/file_ops/ioctl/builtin.rs b/src/libos/src/fs/file_ops/ioctl/builtin.rs index 710ece74..0af50d65 100644 --- a/src/libos/src/fs/file_ops/ioctl/builtin.rs +++ b/src/libos/src/fs/file_ops/ioctl/builtin.rs @@ -25,3 +25,20 @@ pub struct IfReq { pub ifr_name: [u8; IFNAMSIZ], pub ifr_union: [u8; 24], } + +type TcflagT = u32; +type CcT = u8; +type SpeedT = u32; +const NCCS: usize = 32; +#[derive(Debug)] +#[repr(C)] +pub struct Termios { + pub c_iflag: TcflagT, + pub c_oflag: TcflagT, + pub c_cflag: TcflagT, + pub c_lflag: TcflagT, + pub c_line: CcT, + pub c_cc: [CcT; NCCS], + pub c_ispeed: SpeedT, + pub c_ospeed: SpeedT, +} diff --git a/src/libos/src/fs/file_ops/ioctl/mod.rs b/src/libos/src/fs/file_ops/ioctl/mod.rs index f04fdeb8..5457815c 100644 --- a/src/libos/src/fs/file_ops/ioctl/mod.rs +++ b/src/libos/src/fs/file_ops/ioctl/mod.rs @@ -26,6 +26,9 @@ impl_ioctl_nums_and_cmds! { // Format: // ioctl_name => (ioctl_num, ioctl_type_arg) + // Get terminal attributes + TCGETS => (0x5401, mut Termios), // ignore + TCSETS => (0x5402, Termios), // Get window size TIOCGWINSZ => (0x5413, mut WinSize), // Set window size diff --git a/src/libos/src/fs/inode_file.rs b/src/libos/src/fs/inode_file.rs index bbbaf948..00126eb6 100644 --- a/src/libos/src/fs/inode_file.rs +++ b/src/libos/src/fs/inode_file.rs @@ -203,6 +203,11 @@ impl File for INodeFile { } fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { + match cmd { + IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"), + IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"), + _ => {} + }; let cmd_num = cmd.cmd_num(); let cmd_argp = cmd.arg_ptr() as usize; self.inode.io_control(cmd_num, cmd_argp)?; diff --git a/src/libos/src/fs/pipe.rs b/src/libos/src/fs/pipe.rs index 5fa195fa..1928138a 100644 --- a/src/libos/src/fs/pipe.rs +++ b/src/libos/src/fs/pipe.rs @@ -87,6 +87,10 @@ impl File for PipeReader { fn as_any(&self) -> &dyn Any { self } + + fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { + ioctl_inner(cmd) + } } pub struct PipeWriter { @@ -150,6 +154,10 @@ impl File for PipeWriter { fn as_any(&self) -> &dyn Any { self } + + fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { + ioctl_inner(cmd) + } } impl fmt::Debug for PipeReader { @@ -202,3 +210,12 @@ impl PipeType for FileRef { .ok_or_else(|| errno!(EBADF, "not a pipe writer")) } } + +fn ioctl_inner(cmd: &mut IoctlCmd) -> Result { + match cmd { + IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"), + IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"), + _ => return_errno!(ENOSYS, "not supported"), + }; + unreachable!(); +} diff --git a/src/libos/src/fs/stdio.rs b/src/libos/src/fs/stdio.rs index 13783d12..991cc2a5 100644 --- a/src/libos/src/fs/stdio.rs +++ b/src/libos/src/fs/stdio.rs @@ -171,6 +171,8 @@ impl File for StdoutFile { fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { let can_delegate_to_host = match cmd { + IoctlCmd::TCGETS(_) => true, + IoctlCmd::TCSETS(_) => true, IoctlCmd::TIOCGWINSZ(_) => true, IoctlCmd::TIOCSWINSZ(_) => true, _ => false, @@ -320,6 +322,8 @@ impl File for StdinFile { fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { let can_delegate_to_host = match cmd { + IoctlCmd::TCGETS(_) => true, + IoctlCmd::TCSETS(_) => true, IoctlCmd::TIOCGWINSZ(_) => true, IoctlCmd::TIOCSWINSZ(_) => true, _ => false, diff --git a/test/ioctl/Makefile b/test/ioctl/Makefile index 1ac31f7c..c7be0387 100644 --- a/test/ioctl/Makefile +++ b/test/ioctl/Makefile @@ -2,7 +2,7 @@ include ../test_common.mk SGX_SDK ?= /opt/intel/sgxsdk -EXTRA_C_FLAGS := -I$(SGX_SDK)/include +EXTRA_C_FLAGS := -I$(SGX_SDK)/include -g ifdef OCCLUM_DISABLE_DCAP EXTRA_C_FLAGS += -DOCCLUM_DISABLE_DCAP diff --git a/test/ioctl/main.c b/test/ioctl/main.c index eddc4bb9..68b16023 100644 --- a/test/ioctl/main.c +++ b/test/ioctl/main.c @@ -36,6 +36,54 @@ int test_tty_ioctl_TIOCGWINSZ(void) { return 0; } +int test_ioctl_TCGETS_TCSETS(void) { + struct termios term; + // FIXME: /dev/tty should be opened. But it has not been implemented in Occlum yet. + // So we just skip this test if STDOUT is redirected. + if (!isatty(STDOUT_FILENO)) { + printf("Warning: test_tty_ioctl_TIOCGWINSZ is skipped\n"); + return 0; + } + + if (ioctl(STDOUT_FILENO, TCGETS, &term) < 0) { + THROW_ERROR("failed to ioctl TCGETS"); + } + + if (ioctl(STDOUT_FILENO, TCSETS, &term) < 0) { + THROW_ERROR("failed to ioctl TCSETS"); + } + + const char *file_path = "/root/test_ioctl.txt"; + int flags = O_RDONLY | O_CREAT | O_TRUNC; + int mode = 00666; + int fd = open(file_path, flags, mode); + if (fd < 0) { + THROW_ERROR("failed to open test file"); + } + + int pipefds[2]; + int ret = pipe(pipefds); + if (ret != 0) { + THROW_ERROR("failed to create pipe"); + } + + ret = ioctl(fd, TCGETS, &term); + if (ret != -1 || errno != ENOTTY) { + THROW_ERROR("failed catch error"); + } + + ret = ioctl(pipefds[0], TCGETS, &term); + if (ret != -1 || errno != ENOTTY) { + THROW_ERROR("failed catch error"); + } + + close(fd); + close(pipefds[0]); + close(pipefds[1]); + + return 0; +} + // ============================================================================ // Test cases for SGX ioctls // ============================================================================ @@ -463,6 +511,7 @@ int test_ioctl_FIONBIO(void) { static test_case_t test_cases[] = { TEST_CASE(test_tty_ioctl_TIOCGWINSZ), + TEST_CASE(test_ioctl_TCGETS_TCSETS), TEST_CASE(test_sgx_ioctl_SGXIOC_IS_EDMM_SUPPORTED), TEST_CASE(test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID), TEST_CASE(test_sgx_ioctl_SGXIOC_GEN_EPID_QUOTE),