[libos] Re-implement ioctl commands
This commit is contained in:
parent
fd6e1bae45
commit
f3b1acf3ce
@ -45,7 +45,7 @@ impl INode for DevSgx {
|
|||||||
|
|
||||||
fn io_control(&self, _cmd: u32, _data: usize) -> vfs::Result<()> {
|
fn io_control(&self, _cmd: u32, _data: usize) -> vfs::Result<()> {
|
||||||
let mut ioctl_cmd =
|
let mut ioctl_cmd =
|
||||||
unsafe { IoctlCmd::new(_cmd, _data as *mut u8).map_err(|_| FsError::InvalidParam)? };
|
unsafe { IoctlRawCmd::new(_cmd, _data as *mut u8).map_err(|_| FsError::InvalidParam)? };
|
||||||
self.ioctl(&mut ioctl_cmd).map_err(|e| {
|
self.ioctl(&mut ioctl_cmd).map_err(|e| {
|
||||||
error!("{}", e.backtrace());
|
error!("{}", e.backtrace());
|
||||||
FsError::IOCTLError
|
FsError::IOCTLError
|
||||||
@ -59,9 +59,9 @@ impl INode for DevSgx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DevSgx {
|
impl DevSgx {
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut IoctlRawCmd) -> Result<i32> {
|
||||||
let nonbuiltin_cmd = match cmd {
|
let nonbuiltin_cmd = match cmd {
|
||||||
IoctlCmd::NonBuiltin(nonbuiltin_cmd) => nonbuiltin_cmd,
|
IoctlRawCmd::NonBuiltin(nonbuiltin_cmd) => nonbuiltin_cmd,
|
||||||
_ => return_errno!(EINVAL, "unknown ioctl cmd for /dev/sgx"),
|
_ => return_errno!(EINVAL, "unknown ioctl cmd for /dev/sgx"),
|
||||||
};
|
};
|
||||||
let cmd_num = nonbuiltin_cmd.cmd_num().as_u32();
|
let cmd_num = nonbuiltin_cmd.cmd_num().as_u32();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::fs::IoctlCmd;
|
||||||
|
|
||||||
macro_rules! return_op_unsupported_error {
|
macro_rules! return_op_unsupported_error {
|
||||||
($op_name: expr, $errno: expr) => {{
|
($op_name: expr, $errno: expr) => {{
|
||||||
@ -79,8 +80,8 @@ pub trait File: Debug + Sync + Send + Any {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, _cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
return_op_unsupported_error!("ioctl")
|
return_op_unsupported_error!("ioctl", EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn access_mode(&self) -> Result<AccessMode> {
|
fn access_mode(&self) -> Result<AccessMode> {
|
||||||
@ -142,7 +143,7 @@ pub trait File: Debug + Sync + Send + Any {
|
|||||||
|
|
||||||
/// Return the host fd, if the file is backed by an underlying host file.
|
/// Return the host fd, if the file is backed by an underlying host file.
|
||||||
fn host_fd(&self) -> Option<&HostFd> {
|
fn host_fd(&self) -> Option<&HostFd> {
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the ready events of a host file.
|
/// Update the ready events of a host file.
|
||||||
|
136
src/libos/src/fs/file_ops/ioctl/builtin/get_ifconf.rs
Normal file
136
src/libos/src/fs/file_ops/ioctl/builtin/get_ifconf.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
use super::IoctlCmd;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct IfConf {
|
||||||
|
pub ifc_len: i32,
|
||||||
|
pub ifc_buf: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GetIfConf {
|
||||||
|
IfConfBuf(Vec<u8>),
|
||||||
|
IfConfLen(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetIfConf {
|
||||||
|
pub fn new(ifconf: &IfConf) -> Self {
|
||||||
|
if ifconf.ifc_buf.is_null() {
|
||||||
|
Self::IfConfLen(ifconf.ifc_len as usize)
|
||||||
|
} else {
|
||||||
|
let buf = {
|
||||||
|
let mut buf = Vec::with_capacity(ifconf.ifc_len as usize);
|
||||||
|
buf.resize(ifconf.ifc_len as usize, 0);
|
||||||
|
buf
|
||||||
|
};
|
||||||
|
Self::IfConfBuf(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&mut self, fd: FileDesc) -> Result<()> {
|
||||||
|
if let Self::IfConfBuf(buf) = self {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut if_conf = self.to_raw_ifconf();
|
||||||
|
get_ifconf_by_host(fd, &mut if_conf)?;
|
||||||
|
self.set_len(if_conf.ifc_len as usize);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_len(&mut self, new_len: usize) {
|
||||||
|
match self {
|
||||||
|
Self::IfConfLen(len) => {
|
||||||
|
*len = new_len;
|
||||||
|
}
|
||||||
|
Self::IfConfBuf(buf) => {
|
||||||
|
buf.resize(new_len, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::IfConfLen(len) => *len,
|
||||||
|
Self::IfConfBuf(buf) => buf.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> Option<&[u8]> {
|
||||||
|
match self {
|
||||||
|
Self::IfConfBuf(buf) => Some(buf.as_slice()),
|
||||||
|
Self::IfConfLen(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_raw_ifconf(&self) -> IfConf {
|
||||||
|
match self {
|
||||||
|
Self::IfConfLen(len) => IfConf {
|
||||||
|
ifc_buf: std::ptr::null(),
|
||||||
|
ifc_len: *len as i32,
|
||||||
|
},
|
||||||
|
Self::IfConfBuf(buf) => IfConf {
|
||||||
|
ifc_buf: buf.as_ptr(),
|
||||||
|
ifc_len: buf.len() as i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoctlCmd for GetIfConf {}
|
||||||
|
|
||||||
|
const SIOCGIFCONF: u32 = 0x8912;
|
||||||
|
|
||||||
|
fn get_ifconf_by_host(fd: FileDesc, if_conf: &mut IfConf) -> Result<()> {
|
||||||
|
extern "C" {
|
||||||
|
// Used to ioctl arguments with pointer members.
|
||||||
|
//
|
||||||
|
// Before the call the area the pointers points to should be assembled into
|
||||||
|
// one continuous memory block. Then the block is repacked to ioctl arguments
|
||||||
|
// in the ocall implementation in host.
|
||||||
|
//
|
||||||
|
// ret: holds the return value of ioctl in host
|
||||||
|
// fd: the host fd for the device
|
||||||
|
// cmd_num: request number of the ioctl
|
||||||
|
// buf: the data to exchange with host
|
||||||
|
// len: the size of the buf
|
||||||
|
// recv_len: accepts transferred data length when buf is used to get data from host
|
||||||
|
//
|
||||||
|
fn socket_ocall_ioctl_repack(
|
||||||
|
ret: *mut i32,
|
||||||
|
fd: i32,
|
||||||
|
cmd_num: i32,
|
||||||
|
buf: *const u8,
|
||||||
|
len: i32,
|
||||||
|
recv_len: *mut i32,
|
||||||
|
) -> sgx_types::sgx_status_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
try_libc!({
|
||||||
|
let mut recv_len: i32 = 0;
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = socket_ocall_ioctl_repack(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
fd as _,
|
||||||
|
SIOCGIFCONF as _,
|
||||||
|
if_conf.ifc_buf,
|
||||||
|
if_conf.ifc_len,
|
||||||
|
&mut recv_len as *mut i32,
|
||||||
|
);
|
||||||
|
assert!(status == sgx_types::sgx_status_t::SGX_SUCCESS);
|
||||||
|
|
||||||
|
// If ifc_req is NULL, SIOCGIFCONF returns the necessary buffer
|
||||||
|
// size in bytes for receiving all available addresses in ifc_len
|
||||||
|
// which is irrelevant to the orginal ifc_len.
|
||||||
|
if !if_conf.ifc_buf.is_null() {
|
||||||
|
assert!(if_conf.ifc_len >= recv_len);
|
||||||
|
}
|
||||||
|
if_conf.ifc_len = recv_len;
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
77
src/libos/src/fs/file_ops/ioctl/builtin/get_ifreq.rs
Normal file
77
src/libos/src/fs/file_ops/ioctl/builtin/get_ifreq.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
const IFNAMSIZ: usize = 16;
|
||||||
|
use super::IoctlCmd;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct IfReq {
|
||||||
|
pub ifr_name: [u8; IFNAMSIZ],
|
||||||
|
pub ifr_union: [u8; 24],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Many of the socket ioctl commands use `IfReq` as the structure to get configuration
|
||||||
|
/// of network devices. The only difference is the command number.
|
||||||
|
///
|
||||||
|
/// This structure wraps the `GetIfReq` and the command number as the `IoctlCmd`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetIfReqWithRawCmd {
|
||||||
|
inner: GetIfReq,
|
||||||
|
raw_cmd: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetIfReqWithRawCmd {
|
||||||
|
pub fn new(raw_cmd: u32, req: IfReq) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: GetIfReq::new(req),
|
||||||
|
raw_cmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn output(&self) -> Option<&IfReq> {
|
||||||
|
self.inner.output()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&mut self, fd: FileDesc) -> Result<()> {
|
||||||
|
let input_if_req = self.inner.input();
|
||||||
|
let output_if_req = get_ifreq_by_host(fd, self.raw_cmd, input_if_req)?;
|
||||||
|
self.inner.set_output(output_if_req);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ifreq_by_host(fd: FileDesc, cmd: u32, req: &IfReq) -> Result<IfReq> {
|
||||||
|
let mut if_req: IfReq = req.clone();
|
||||||
|
try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
extern "C" {
|
||||||
|
pub fn occlum_ocall_ioctl(
|
||||||
|
ret: *mut i32,
|
||||||
|
fd: c_int,
|
||||||
|
request: c_int,
|
||||||
|
arg: *mut c_void,
|
||||||
|
len: size_t,
|
||||||
|
) -> sgx_types::sgx_status_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
use libc::{c_int, c_void, size_t};
|
||||||
|
use occlum_ocall_ioctl as do_ioctl;
|
||||||
|
|
||||||
|
let status = do_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
fd as i32,
|
||||||
|
cmd as i32,
|
||||||
|
&mut if_req as *mut IfReq as *mut c_void,
|
||||||
|
std::mem::size_of::<IfReq>(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_types::sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
Ok(if_req)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoctlCmd for GetIfReqWithRawCmd {}
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct GetIfReq<Input=IfReq, Output=IfReq> {}
|
||||||
|
}
|
28
src/libos/src/fs/file_ops/ioctl/builtin/get_readbuflen.rs
Normal file
28
src/libos/src/fs/file_ops/ioctl/builtin/get_readbuflen.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct GetReadBufLen<Input=(), Output=i32> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetReadBufLen {
|
||||||
|
pub fn execute(&mut self, host_fd: FileDesc) -> Result<()> {
|
||||||
|
let mut buflen: i32 = 0;
|
||||||
|
|
||||||
|
try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
host_fd as i32,
|
||||||
|
BuiltinIoctlNum::FIONREAD as i32,
|
||||||
|
&mut buflen as *mut i32 as *mut c_void,
|
||||||
|
std::mem::size_of::<i32>(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
|
||||||
|
trace!("read buf len = {:?}", buflen);
|
||||||
|
self.set_output(buflen);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
310
src/libos/src/fs/file_ops/ioctl/builtin/mod.rs
Normal file
310
src/libos/src/fs/file_ops/ioctl/builtin/mod.rs
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
//! An ioctl-style, extensible API for file types.
|
||||||
|
//!
|
||||||
|
//! # Motiviation
|
||||||
|
//!
|
||||||
|
//! Let's consider three classic versatile APIs for files in Unix-like
|
||||||
|
//! systems: `ioctl`, `fcntl`, and `getsockopt`/`setsockopt`.
|
||||||
|
//!
|
||||||
|
//! ```c
|
||||||
|
//! int fcntl(int fd, int cmd, ... /* arg */ );
|
||||||
|
//!
|
||||||
|
//! int ioctl(int fd, unsigned long request, ... /* arg */);
|
||||||
|
//!
|
||||||
|
//! int getsockopt(int sockfd, int level, int optname,
|
||||||
|
//! void *restrict optval, socklen_t *restrict optlen);
|
||||||
|
//! int setsockopt(int sockfd, int level, int optname,
|
||||||
|
//! const void *optval, socklen_t optlen);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The three APIs have two properties in common: _extensibility_ and
|
||||||
|
//! _type erasure_. By extensibility, we mean that it is quite easy to add
|
||||||
|
//! new sub-commands that are specific to a device or file. And type erasure
|
||||||
|
//! underscores the fact that since the input and output arguments of a future
|
||||||
|
//! sub-command cannot be known beforehand, the concrete types of these
|
||||||
|
//! arguments have to be "erased" from the interface using `...` or `void*`.
|
||||||
|
//!
|
||||||
|
//! So how do we support these three C APIs in our Rust types for files?
|
||||||
|
//!
|
||||||
|
//! Specifically, do we need to add three separate Rust APIs corresponding to
|
||||||
|
//! their C counterparts? And what is the best way to express type-erased
|
||||||
|
//! arguments in the type-safe language of Rust? And most importantly, how
|
||||||
|
//! can we add new kinds of sub-commands and handle all kinds of sub-commands
|
||||||
|
//! as painless as possible?
|
||||||
|
//!
|
||||||
|
//! Our solution is the `IoctlCmd` trait and its companion macros.
|
||||||
|
//!
|
||||||
|
//! # Usage
|
||||||
|
//!
|
||||||
|
//! Here is a simple program to demonstrate the usage of `IoctlCmd`.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use net::{impl_ioctl_cmd, match_ioctl_cmd_mut};
|
||||||
|
//! use net::ioctl::{IoctlCmd};
|
||||||
|
//!
|
||||||
|
//! /// A trait to abstract any file-like type.
|
||||||
|
//! ///
|
||||||
|
//! /// For our purpose, it suffices for the trait to have only one API,
|
||||||
|
//! /// which takes a mutable trait object of `IoctlCmd` as its argument.
|
||||||
|
//! /// Thanks to `IoctlCmd`'s capability of downcasting itself to the
|
||||||
|
//! /// concrete type that implements the trait, it becomes easy to accept
|
||||||
|
//! /// all kinds of commands without breaking changes to the API signature.
|
||||||
|
//! pub trait File {
|
||||||
|
//! fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()>;
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // A typical command consists of an input and an output. For such commands,
|
||||||
|
//! // you can use the `impl_ioctl_cmd` to define them handily.
|
||||||
|
//! //
|
||||||
|
//! // Here, three structs are defined, implementing the `IoctlCmd` trait.
|
||||||
|
//! // Each of them represent a different command, having different
|
||||||
|
//! // input and output arguments.
|
||||||
|
//! //
|
||||||
|
//! // Note that while the trait is named `IoctlCmd`, it does not
|
||||||
|
//! // preclude using the trait to abstract `fcntl` or `getsocktopt`
|
||||||
|
//! // commands.
|
||||||
|
//! impl_ioctl_cmd! {
|
||||||
|
//! pub struct CommonCmd<Input=(), Output=bool> {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl_ioctl_cmd! {
|
||||||
|
//! pub struct FooCmd<Input=i32, Output=()> {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl_ioctl_cmd! {
|
||||||
|
//! pub struct BarCmd<Input=i32, Output=String> {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // Of course. You can implement an ioctl command manually, without
|
||||||
|
//! // using the `impl_ioctl_cmd` macro.
|
||||||
|
//! #[derive(Debug)]
|
||||||
|
//! pub struct ComplexCmd { /* customized memory layout */ };
|
||||||
|
//! impl IoctlCmd for ComplexCmd {}
|
||||||
|
//!
|
||||||
|
//! pub struct FooFile;
|
||||||
|
//! impl File for FooFile {
|
||||||
|
//! fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
|
//! // Only handle the interesting commands. The trait object
|
||||||
|
//! // is automatically downcasted to the concrete struct that
|
||||||
|
//! // represents the command.
|
||||||
|
//! match_ioctl_cmd_mut!(&mut *cmd, {
|
||||||
|
//! cmd: CommonCmd => {
|
||||||
|
//! println!("Accepted CommonCmd: {:?}", cmd);
|
||||||
|
//! Ok(())
|
||||||
|
//! },
|
||||||
|
//! cmd: FooCmd => {
|
||||||
|
//! println!("FooCmd's input: {}", cmd.input());
|
||||||
|
//! Ok(())
|
||||||
|
//! },
|
||||||
|
//! _ => {
|
||||||
|
//! Err(errno!(EINVAL, "unknown command"))
|
||||||
|
//! }
|
||||||
|
//! })
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! pub struct BarFile;
|
||||||
|
//! impl File for BarFile {
|
||||||
|
//! fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
|
//! match_ioctl_cmd_mut!(&mut *cmd, {
|
||||||
|
//! cmd: CommonCmd => {
|
||||||
|
//! println!("Accepted CommonCmd: {:?}", cmd);
|
||||||
|
//! Ok(())
|
||||||
|
//! },
|
||||||
|
//! cmd: BarCmd => {
|
||||||
|
//! cmd.set_output("Bar Result".to_string());
|
||||||
|
//! println!("BarCmd's output: {}", cmd.output().unwrap());
|
||||||
|
//! Ok(())
|
||||||
|
//! },
|
||||||
|
//! cmd: ComplexCmd => {
|
||||||
|
//! println!("Accepted ComplexCmd: {:?}", cmd);
|
||||||
|
//! Ok(())
|
||||||
|
//! },
|
||||||
|
//! _ => {
|
||||||
|
//! Err(errno!(EINVAL, "unknown command"))
|
||||||
|
//! }
|
||||||
|
//! })
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
/// A trait to unify all concrete types representing ioctl commands.
|
||||||
|
///
|
||||||
|
/// The most useful property of this trait is that it supports downcasting
|
||||||
|
/// to the concrete type that actually implements the trait with the
|
||||||
|
/// `downcast_ref` and `downcast_mut` methods.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use async_io::ioctl::IoctlCmd;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug)]
|
||||||
|
/// pub struct DummyCmd;
|
||||||
|
/// impl IoctlCmd for DummyCmd {}
|
||||||
|
///
|
||||||
|
/// let dummy : Box<dyn IoctlCmd> = Box::new(DummyCmd);
|
||||||
|
/// assert!(dummy.downcast_ref::<DummyCmd>().is_some());
|
||||||
|
/// ```
|
||||||
|
pub trait IoctlCmd: Downcast + Debug + Sync + Send {}
|
||||||
|
impl_downcast!(IoctlCmd);
|
||||||
|
|
||||||
|
/// A convenient macro to define a struct for some type of ioctl command.
|
||||||
|
///
|
||||||
|
/// Typcially, an ioctl command consists of an input argument and an output
|
||||||
|
/// output. As such, the struct defined by this macro has two fields: the
|
||||||
|
/// input and the output.
|
||||||
|
///
|
||||||
|
/// The struct defined by this macro automatically implements the `IoctlCmd`
|
||||||
|
/// trait.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_ioctl_cmd {
|
||||||
|
(
|
||||||
|
$(#[$outer:meta])*
|
||||||
|
pub struct $CmdName:ident <Input=$Input:ty, Output=$Output:ty> {}
|
||||||
|
) => {
|
||||||
|
$(#[$outer])*
|
||||||
|
pub struct $CmdName {
|
||||||
|
input: $Input,
|
||||||
|
output: Option<$Output>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl $CmdName {
|
||||||
|
pub fn new(input: $Input) -> Self {
|
||||||
|
Self {
|
||||||
|
input,
|
||||||
|
output: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input(&self) -> &$Input {
|
||||||
|
&self.input
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn output(&self) -> Option<&$Output> {
|
||||||
|
self.output.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_output(&mut self, output: $Output) {
|
||||||
|
self.output = Some(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_output(&mut self) -> Option<$Output> {
|
||||||
|
self.output.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::fs::IoctlCmd for $CmdName {}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for $CmdName {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct(stringify!($CmdName))
|
||||||
|
.field("input", self.input())
|
||||||
|
.field("output", &self.output())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub use self::get_ifconf::{GetIfConf, IfConf};
|
||||||
|
pub use self::get_ifreq::{GetIfReq, GetIfReqWithRawCmd, IfReq};
|
||||||
|
pub use self::get_readbuflen::GetReadBufLen;
|
||||||
|
pub use self::set_close_on_exec::*;
|
||||||
|
pub use self::set_nonblocking::SetNonBlocking;
|
||||||
|
pub use self::termios::*;
|
||||||
|
pub use self::winsize::*;
|
||||||
|
pub use net::socket::sockopt::SetSockOptRawCmd;
|
||||||
|
|
||||||
|
mod get_ifconf;
|
||||||
|
mod get_ifreq;
|
||||||
|
mod get_readbuflen;
|
||||||
|
mod set_close_on_exec;
|
||||||
|
mod set_nonblocking;
|
||||||
|
mod termios;
|
||||||
|
mod winsize;
|
||||||
|
|
||||||
|
use downcast_rs::{impl_downcast, Downcast};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! match_ioctl_cmd_ref {
|
||||||
|
(
|
||||||
|
$cmd:expr,
|
||||||
|
{
|
||||||
|
$( $bind:ident : $ty:ty => $arm:expr ),*,
|
||||||
|
_ => $default:expr
|
||||||
|
}
|
||||||
|
) => {{
|
||||||
|
let __cmd : &dyn crate::fs::IoctlCmd = $cmd;
|
||||||
|
$(
|
||||||
|
if __cmd.is::<$ty>() {
|
||||||
|
let $bind = __cmd.downcast_ref::<$ty>().unwrap();
|
||||||
|
$arm
|
||||||
|
} else
|
||||||
|
)*
|
||||||
|
{
|
||||||
|
$default
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! match_ioctl_cmd_mut {
|
||||||
|
(
|
||||||
|
$cmd:expr,
|
||||||
|
{
|
||||||
|
$( $bind:ident : $ty:ty => $arm:expr ),*,
|
||||||
|
_ => $default:expr
|
||||||
|
}
|
||||||
|
) => {{
|
||||||
|
let __cmd : &mut dyn crate::fs::IoctlCmd = $cmd;
|
||||||
|
$(
|
||||||
|
if __cmd.is::<$ty>() {
|
||||||
|
let $bind = __cmd.downcast_mut::<$ty>().unwrap();
|
||||||
|
$arm
|
||||||
|
} else
|
||||||
|
)*
|
||||||
|
{
|
||||||
|
$default
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Macro for ioctl auto error number.
|
||||||
|
// If the corresponding cmds are not defined, a default error number will be return
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! match_ioctl_cmd_auto_error {
|
||||||
|
(
|
||||||
|
$cmd:expr,
|
||||||
|
{
|
||||||
|
$( $bind:ident : $ty:ty => $arm:expr ),* $(,)?
|
||||||
|
}
|
||||||
|
) => {{
|
||||||
|
use crate::fs::*;
|
||||||
|
let __cmd : &mut dyn crate::fs::IoctlCmd = $cmd;
|
||||||
|
$(
|
||||||
|
if __cmd.is::<$ty>() {
|
||||||
|
let $bind = __cmd.downcast_mut::<$ty>().unwrap();
|
||||||
|
$arm
|
||||||
|
} else
|
||||||
|
)*
|
||||||
|
// If the corresponding cmds are not defined, it will go here for default error
|
||||||
|
if __cmd.is::<TcGets>() {
|
||||||
|
return_errno!(Errno::ENOTTY, "not tty device");
|
||||||
|
}
|
||||||
|
else if __cmd.is::<TcSets>() {
|
||||||
|
return_errno!(Errno::ENOTTY, "not tty device");
|
||||||
|
}
|
||||||
|
else if __cmd.is::<GetWinSize>() {
|
||||||
|
return_errno!(Errno::ENOTTY, "not tty device");
|
||||||
|
}
|
||||||
|
else if __cmd.is::<SetWinSize>() {
|
||||||
|
return_errno!(Errno::ENOTTY, "not tty device");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Default branch
|
||||||
|
return_errno!(EINVAL, "unsupported ioctl cmd");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct SetCloseOnExec<Input=bool, Output=()> {}
|
||||||
|
}
|
24
src/libos/src/fs/file_ops/ioctl/builtin/set_nonblocking.rs
Normal file
24
src/libos/src/fs/file_ops/ioctl/builtin/set_nonblocking.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct SetNonBlocking<Input=i32, Output=()> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetNonBlocking {
|
||||||
|
pub fn execute(&mut self, host_fd: FileDesc) -> Result<()> {
|
||||||
|
try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
host_fd as i32,
|
||||||
|
BuiltinIoctlNum::FIONBIO as i32,
|
||||||
|
self.input() as *const i32 as *mut c_void,
|
||||||
|
std::mem::size_of::<i32>(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +1,5 @@
|
|||||||
//! Built-in ioctls.
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct WinSize {
|
|
||||||
pub ws_row: u16,
|
|
||||||
pub ws_col: u16,
|
|
||||||
pub ws_xpixel: u16,
|
|
||||||
pub ws_ypixel: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct IfConf {
|
|
||||||
pub ifc_len: i32,
|
|
||||||
pub ifc_buf: *const u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
const IFNAMSIZ: usize = 16;
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct IfReq {
|
|
||||||
pub ifr_name: [u8; IFNAMSIZ],
|
|
||||||
pub ifr_union: [u8; 24],
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The termios structure used in the Linux kernel is not the same as we use in the glibc. Thus, we have two
|
The termios structure used in the Linux kernel is not the same as we use in the glibc. Thus, we have two
|
||||||
definitions here.
|
definitions here.
|
||||||
@ -78,49 +52,10 @@ impl KernelTermios {
|
|||||||
c_ospeed: 0,
|
c_ospeed: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_tcgets(&mut self, host_fd: i32, cmd_num: i32) -> Result<i32> {
|
|
||||||
debug_assert!(cmd_num == 0x5401);
|
|
||||||
let mut termios = self.to_termios();
|
|
||||||
let len = std::mem::size_of::<Termios>();
|
|
||||||
let ret = try_libc!({
|
|
||||||
let mut retval: i32 = 0;
|
|
||||||
let status = occlum_ocall_ioctl(
|
|
||||||
&mut retval as *mut i32,
|
|
||||||
host_fd,
|
|
||||||
cmd_num,
|
|
||||||
&mut termios as *const Termios as *mut c_void,
|
|
||||||
len,
|
|
||||||
);
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
retval
|
|
||||||
});
|
|
||||||
*self = termios.to_kernel_termios();
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_tcsets(&self, host_fd: i32, cmd_num: i32) -> Result<i32> {
|
|
||||||
debug_assert!(cmd_num == 0x5402);
|
|
||||||
let termios = self.to_termios();
|
|
||||||
let len = std::mem::size_of::<Termios>();
|
|
||||||
let ret = try_libc!({
|
|
||||||
let mut retval: i32 = 0;
|
|
||||||
let status = occlum_ocall_ioctl(
|
|
||||||
&mut retval as *mut i32,
|
|
||||||
host_fd,
|
|
||||||
cmd_num,
|
|
||||||
&termios as *const Termios as *mut c_void,
|
|
||||||
len,
|
|
||||||
);
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
retval
|
|
||||||
});
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Termios {
|
impl Termios {
|
||||||
pub fn to_kernel_termios(&self) -> KernelTermios {
|
fn to_kernel_termios(&self) -> KernelTermios {
|
||||||
let mut c_cc = [0; KERNEL_NCCS];
|
let mut c_cc = [0; KERNEL_NCCS];
|
||||||
c_cc.copy_from_slice(&self.c_cc[..KERNEL_NCCS]);
|
c_cc.copy_from_slice(&self.c_cc[..KERNEL_NCCS]);
|
||||||
|
|
||||||
@ -134,3 +69,55 @@ impl Termios {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct TcGets<Input=(), Output=KernelTermios> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TcGets {
|
||||||
|
pub fn execute(&mut self, host_fd: FileDesc) -> Result<()> {
|
||||||
|
let mut termios: Termios = Default::default();
|
||||||
|
|
||||||
|
try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
host_fd as i32,
|
||||||
|
BuiltinIoctlNum::TCGETS as i32,
|
||||||
|
&mut termios as *mut Termios as *mut c_void,
|
||||||
|
std::mem::size_of::<Termios>(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
|
||||||
|
let kernel_termios = termios.to_kernel_termios();
|
||||||
|
trace!("kernel termios = {:?}", kernel_termios);
|
||||||
|
self.set_output(kernel_termios);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct TcSets<Input=KernelTermios, Output=()> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TcSets {
|
||||||
|
pub fn execute(&self, host_fd: FileDesc) -> Result<()> {
|
||||||
|
let kernel_termios = self.input();
|
||||||
|
let termios = kernel_termios.to_termios();
|
||||||
|
try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
host_fd as i32,
|
||||||
|
BuiltinIoctlNum::TCSETS as i32,
|
||||||
|
&termios as *const Termios as *mut c_void,
|
||||||
|
std::mem::size_of::<Termios>(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
64
src/libos/src/fs/file_ops/ioctl/builtin/winsize.rs
Normal file
64
src/libos/src/fs/file_ops/ioctl/builtin/winsize.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WinSize {
|
||||||
|
pub ws_row: u16,
|
||||||
|
pub ws_col: u16,
|
||||||
|
pub ws_xpixel: u16,
|
||||||
|
pub ws_ypixel: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct SetWinSize<Input=WinSize, Output=()> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetWinSize {
|
||||||
|
pub fn execute(&self, host_fd: FileDesc) -> Result<()> {
|
||||||
|
try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
host_fd as i32,
|
||||||
|
BuiltinIoctlNum::TIOCSWINSZ as i32,
|
||||||
|
self.input() as *const WinSize as *mut c_void,
|
||||||
|
std::mem::size_of::<WinSize>(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_ioctl_cmd! {
|
||||||
|
pub struct GetWinSize<Input=(), Output=WinSize> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetWinSize {
|
||||||
|
pub fn execute(&mut self, host_fd: FileDesc) -> Result<()> {
|
||||||
|
let mut winsize: WinSize = Default::default();
|
||||||
|
|
||||||
|
try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
host_fd as i32,
|
||||||
|
BuiltinIoctlNum::TIOCGWINSZ as i32,
|
||||||
|
&mut winsize as *mut WinSize as *mut c_void,
|
||||||
|
std::mem::size_of::<WinSize>(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
|
||||||
|
if winsize.ws_row == 0 || winsize.ws_col == 0 {
|
||||||
|
warn!(
|
||||||
|
"window size: row: {:?}, col: {:?}",
|
||||||
|
winsize.ws_row, winsize.ws_col
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.set_output(winsize);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
//! Macros to implement `BuiltinIoctlNum` and `IoctlCmd` given a list of ioctl
|
//! Macros to implement `BuiltinIoctlNum` and `IoctlRawCmd` given a list of ioctl
|
||||||
//! names, numbers, and argument types.
|
//! names, numbers, and argument types.
|
||||||
|
|
||||||
/// Implement `BuiltinIoctlNum` and `IoctlCmd`.
|
/// Implement `BuiltinIoctlNum` and `IoctlRawCmd`.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_ioctl_nums_and_cmds {
|
macro_rules! impl_ioctl_nums_and_cmds {
|
||||||
($( $ioctl_name: ident => ( $ioctl_num: expr, $($ioctl_type_tt: tt)* ) ),+,) => {
|
($( $ioctl_name: ident => ( $ioctl_num: expr, $($ioctl_type_tt: tt)* ) ),+,) => {
|
||||||
@ -12,7 +12,7 @@ macro_rules! impl_ioctl_nums_and_cmds {
|
|||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement IoctlCmd given ioctl names and their argument types
|
// Implement IoctlRawCmd given ioctl names and their argument types
|
||||||
impl_ioctl_cmds! {
|
impl_ioctl_cmds! {
|
||||||
$(
|
$(
|
||||||
$ioctl_name => ( $($ioctl_type_tt)*),
|
$ioctl_name => ( $($ioctl_type_tt)*),
|
||||||
@ -57,21 +57,21 @@ macro_rules! impl_builtin_ioctl_nums {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// IoctlCmd
|
// IoctlRawCmd
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! impl_ioctl_cmds {
|
macro_rules! impl_ioctl_cmds {
|
||||||
($( $ioctl_name: ident => ( $($ioctl_type_tt: tt)* ) ),+,) => {
|
($( $ioctl_name: ident => ( $($ioctl_type_tt: tt)* ) ),+,) => {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum IoctlCmd<'a> {
|
pub enum IoctlRawCmd<'a> {
|
||||||
$(
|
$(
|
||||||
$ioctl_name( get_arg_type!($($ioctl_type_tt)*) ),
|
$ioctl_name( get_arg_type!($($ioctl_type_tt)*) ),
|
||||||
)*
|
)*
|
||||||
NonBuiltin(NonBuiltinIoctlCmd<'a>),
|
NonBuiltin(NonBuiltinIoctlCmd<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IoctlCmd<'a> {
|
impl<'a> IoctlRawCmd<'a> {
|
||||||
pub unsafe fn new(cmd_num: u32, arg_ptr: *mut u8) -> Result<IoctlCmd<'a>> {
|
pub unsafe fn new(cmd_num: u32, arg_ptr: *mut u8) -> Result<IoctlRawCmd<'a>> {
|
||||||
if let Some(builtin_cmd_num) = BuiltinIoctlNum::from_u32(cmd_num) {
|
if let Some(builtin_cmd_num) = BuiltinIoctlNum::from_u32(cmd_num) {
|
||||||
unsafe { Self::new_builtin_cmd(builtin_cmd_num, arg_ptr) }
|
unsafe { Self::new_builtin_cmd(builtin_cmd_num, arg_ptr) }
|
||||||
} else {
|
} else {
|
||||||
@ -79,7 +79,7 @@ macro_rules! impl_ioctl_cmds {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn new_builtin_cmd(cmd_num: BuiltinIoctlNum, arg_ptr: *mut u8) -> Result<IoctlCmd<'a>> {
|
unsafe fn new_builtin_cmd(cmd_num: BuiltinIoctlNum, arg_ptr: *mut u8) -> Result<IoctlRawCmd<'a>> {
|
||||||
if cmd_num.require_arg() && arg_ptr.is_null() {
|
if cmd_num.require_arg() && arg_ptr.is_null() {
|
||||||
return_errno!(EINVAL, "arg_ptr cannot be null");
|
return_errno!(EINVAL, "arg_ptr cannot be null");
|
||||||
}
|
}
|
||||||
@ -90,43 +90,43 @@ macro_rules! impl_ioctl_cmds {
|
|||||||
$(
|
$(
|
||||||
BuiltinIoctlNum::$ioctl_name => {
|
BuiltinIoctlNum::$ioctl_name => {
|
||||||
let arg = get_arg!($($ioctl_type_tt)*, arg_ptr);
|
let arg = get_arg!($($ioctl_type_tt)*, arg_ptr);
|
||||||
IoctlCmd::$ioctl_name(arg)
|
IoctlRawCmd::$ioctl_name(arg)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
Ok(cmd)
|
Ok(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn new_nonbuiltin_cmd(cmd_num: u32, arg_ptr: *mut u8) -> Result<IoctlCmd<'a>> {
|
unsafe fn new_nonbuiltin_cmd(cmd_num: u32, arg_ptr: *mut u8) -> Result<IoctlRawCmd<'a>> {
|
||||||
let structured_cmd_num = StructuredIoctlNum::from_u32(cmd_num)?;
|
let structured_cmd_num = StructuredIoctlNum::from_u32(cmd_num)?;
|
||||||
let inner_cmd = unsafe { NonBuiltinIoctlCmd::new(structured_cmd_num, arg_ptr)? };
|
let inner_cmd = unsafe { NonBuiltinIoctlCmd::new(structured_cmd_num, arg_ptr)? };
|
||||||
Ok(IoctlCmd::NonBuiltin(inner_cmd))
|
Ok(IoctlRawCmd::NonBuiltin(inner_cmd))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg_ptr(&self) -> *const u8 {
|
pub fn arg_ptr(&self) -> *const u8 {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
IoctlCmd::$ioctl_name(arg_ref) => get_arg_ptr!($($ioctl_type_tt)*, arg_ref),
|
IoctlRawCmd::$ioctl_name(arg_ref) => get_arg_ptr!($($ioctl_type_tt)*, arg_ref),
|
||||||
)*
|
)*
|
||||||
IoctlCmd::NonBuiltin(inner) => inner.arg_ptr(),
|
IoctlRawCmd::NonBuiltin(inner) => inner.arg_ptr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg_len(&self) -> usize {
|
pub fn arg_len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
IoctlCmd::$ioctl_name(_) => get_arg_len!($($ioctl_type_tt)*),
|
IoctlRawCmd::$ioctl_name(_) => get_arg_len!($($ioctl_type_tt)*),
|
||||||
)*
|
)*
|
||||||
IoctlCmd::NonBuiltin(inner) => inner.arg_len(),
|
IoctlRawCmd::NonBuiltin(inner) => inner.arg_len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmd_num(&self) -> u32 {
|
pub fn cmd_num(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
IoctlCmd::$ioctl_name(_) => BuiltinIoctlNum::$ioctl_name as u32,
|
IoctlRawCmd::$ioctl_name(_) => BuiltinIoctlNum::$ioctl_name as u32,
|
||||||
)*
|
)*
|
||||||
IoctlCmd::NonBuiltin(inner) => inner.cmd_num().as_u32(),
|
IoctlRawCmd::NonBuiltin(inner) => inner.cmd_num().as_u32(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,13 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub use self::builtin::*;
|
use self::builtin::*;
|
||||||
|
pub use self::builtin::{
|
||||||
|
GetIfConf, GetIfReqWithRawCmd, GetReadBufLen, GetWinSize, IfConf, IoctlCmd, SetNonBlocking,
|
||||||
|
SetWinSize, TcGets, TcSets,
|
||||||
|
};
|
||||||
pub use self::non_builtin::{NonBuiltinIoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
pub use self::non_builtin::{NonBuiltinIoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
||||||
|
use crate::util::mem_util::from_user;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
@ -18,7 +23,7 @@ mod non_builtin;
|
|||||||
///
|
///
|
||||||
/// By giving the names, numbers, and argument types of built-in ioctls,
|
/// By giving the names, numbers, and argument types of built-in ioctls,
|
||||||
/// the macro below generates the corresponding code of `BuiltinIoctlNum` and
|
/// the macro below generates the corresponding code of `BuiltinIoctlNum` and
|
||||||
/// `IoctlCmd`.
|
/// `IoctlRawCmd`.
|
||||||
///
|
///
|
||||||
/// To add a new built-in ioctl, just follow the convention as shown
|
/// To add a new built-in ioctl, just follow the convention as shown
|
||||||
/// by existing built-in ioctls.
|
/// by existing built-in ioctls.
|
||||||
@ -68,51 +73,121 @@ impl_ioctl_nums_and_cmds! {
|
|||||||
///
|
///
|
||||||
/// Sanity checks are mostly useful when the argument values are returned from
|
/// Sanity checks are mostly useful when the argument values are returned from
|
||||||
/// the untrusted host OS.
|
/// the untrusted host OS.
|
||||||
impl<'a> IoctlCmd<'a> {
|
impl<'a> IoctlRawCmd<'a> {
|
||||||
pub fn validate_arg_and_ret_vals(&self, ret: i32) -> Result<()> {
|
pub fn to_safe_ioctlcmd(&self) -> Result<Box<dyn IoctlCmd>> {
|
||||||
|
Ok(match self {
|
||||||
|
IoctlRawCmd::TCGETS(_) => Box::new(TcGets::new(())),
|
||||||
|
IoctlRawCmd::TCSETS(termios_ref) => {
|
||||||
|
let termios = **termios_ref;
|
||||||
|
Box::new(TcSets::new(termios))
|
||||||
|
}
|
||||||
|
IoctlRawCmd::TIOCGWINSZ(_) => Box::new(GetWinSize::new(())),
|
||||||
|
IoctlRawCmd::TIOCSWINSZ(winsize_ref) => {
|
||||||
|
let winsize = **winsize_ref;
|
||||||
|
Box::new(SetWinSize::new(winsize))
|
||||||
|
}
|
||||||
|
IoctlRawCmd::NonBuiltin(inner) => {
|
||||||
|
let nonbuiltin_cmd =
|
||||||
|
unsafe { NonBuiltinIoctlCmd::new(*inner.cmd_num(), inner.arg_ptr() as _)? };
|
||||||
|
Box::new(nonbuiltin_cmd)
|
||||||
|
}
|
||||||
|
IoctlRawCmd::FIONBIO(non_blocking) => Box::new(SetNonBlocking::new(**non_blocking)),
|
||||||
|
IoctlRawCmd::FIONREAD(_) => Box::new(GetReadBufLen::new(())),
|
||||||
|
IoctlRawCmd::FIONCLEX(_) => Box::new(SetCloseOnExec::new(false)),
|
||||||
|
IoctlRawCmd::FIOCLEX(_) => Box::new(SetCloseOnExec::new(true)),
|
||||||
|
IoctlRawCmd::SIOCGIFCONF(ifconf_mut) => {
|
||||||
|
if !ifconf_mut.ifc_buf.is_null() {
|
||||||
|
if ifconf_mut.ifc_len < 0 {
|
||||||
|
return_errno!(EINVAL, "invalid ifc_len");
|
||||||
|
}
|
||||||
|
from_user::check_array(ifconf_mut.ifc_buf, ifconf_mut.ifc_len as usize)?;
|
||||||
|
}
|
||||||
|
Box::new(GetIfConf::new(ifconf_mut))
|
||||||
|
}
|
||||||
|
IoctlRawCmd::SIOCGIFFLAGS(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFNAME(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFADDR(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFDSTADDR(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFBRDADDR(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFNETMASK(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFMTU(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFHWADDR(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFINDEX(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFPFLAGS(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFTXQLEN(req)
|
||||||
|
| IoctlRawCmd::SIOCGIFMAP(req) => {
|
||||||
|
Box::new(GetIfReqWithRawCmd::new(self.cmd_num(), **req))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return_errno!(EINVAL, "unsupported cmd");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_output_from_safe(&mut self, cmd: &dyn IoctlCmd) {
|
||||||
match self {
|
match self {
|
||||||
IoctlCmd::TIOCGWINSZ(winsize_ref) => {
|
IoctlRawCmd::TCGETS(termios_mut) => {
|
||||||
// ws_row and ws_col are usually not zeros
|
let cmd = cmd.downcast_ref::<TcGets>().unwrap();
|
||||||
if winsize_ref.ws_row == 0 || winsize_ref.ws_col == 0 {
|
**termios_mut = *cmd.output().unwrap();
|
||||||
warn!(
|
}
|
||||||
"window size: row: {:?}, col: {:?}",
|
IoctlRawCmd::TIOCGWINSZ(winsize_mut) => {
|
||||||
winsize_ref.ws_row, winsize_ref.ws_col
|
let cmd = cmd.downcast_ref::<GetWinSize>().unwrap();
|
||||||
);
|
**winsize_mut = *cmd.output().unwrap();
|
||||||
|
}
|
||||||
|
IoctlRawCmd::FIONREAD(len_mut) => {
|
||||||
|
let cmd = cmd.downcast_ref::<GetReadBufLen>().unwrap();
|
||||||
|
**len_mut = *cmd.output().unwrap();
|
||||||
|
}
|
||||||
|
IoctlRawCmd::SIOCGIFCONF(ifconf_mut) => {
|
||||||
|
let cmd = cmd.downcast_ref::<GetIfConf>().unwrap();
|
||||||
|
ifconf_mut.ifc_len = cmd.len() as i32;
|
||||||
|
if !ifconf_mut.ifc_buf.is_null() {
|
||||||
|
let mut raw_buf = unsafe {
|
||||||
|
std::slice::from_raw_parts_mut(
|
||||||
|
ifconf_mut.ifc_buf as _,
|
||||||
|
ifconf_mut.ifc_len as _,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
raw_buf.copy_from_slice(cmd.as_slice().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IoctlCmd::FIONREAD(nread_ref) => {
|
IoctlRawCmd::SIOCGIFNAME(ifreq_mut)
|
||||||
if (**nread_ref < 0) {
|
| IoctlRawCmd::SIOCGIFFLAGS(ifreq_mut)
|
||||||
return_errno!(EINVAL, "invalid data from host");
|
| IoctlRawCmd::SIOCGIFADDR(ifreq_mut)
|
||||||
}
|
| IoctlRawCmd::SIOCGIFDSTADDR(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFBRDADDR(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFNETMASK(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFMTU(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFHWADDR(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFINDEX(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFPFLAGS(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFTXQLEN(ifreq_mut)
|
||||||
|
| IoctlRawCmd::SIOCGIFMAP(ifreq_mut) => {
|
||||||
|
let cmd = cmd.downcast_ref::<GetIfReqWithRawCmd>().unwrap();
|
||||||
|
**ifreq_mut = *cmd.output().unwrap();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current ioctl commands all return zero
|
|
||||||
if ret != 0 {
|
|
||||||
return_errno!(EINVAL, "return value should be zero");
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_ioctl(fd: FileDesc, cmd: &mut IoctlCmd) -> Result<i32> {
|
pub fn do_ioctl(fd: FileDesc, raw_cmd: &mut IoctlRawCmd<'_>) -> Result<i32> {
|
||||||
debug!("ioctl: fd: {}, cmd: {:?}", fd, cmd);
|
debug!("ioctl: fd: {}, cmd: {:?}", fd, raw_cmd);
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let file_ref = current.file(fd)?;
|
let file_ref = current.file(fd)?;
|
||||||
let mut file_table = current.files().lock().unwrap();
|
let mut cmd = raw_cmd.to_safe_ioctlcmd()?;
|
||||||
let mut entry = file_table.get_entry_mut(fd)?;
|
|
||||||
match cmd {
|
if cmd.is::<SetCloseOnExec>() {
|
||||||
IoctlCmd::FIONCLEX(_) => {
|
let is_close_on_exec = cmd.downcast_ref::<SetCloseOnExec>().unwrap().input();
|
||||||
entry.set_close_on_spawn(false);
|
let mut file_table = current.files().lock();
|
||||||
|
let entry = file_table.get_entry_mut(fd)?;
|
||||||
|
entry.set_close_on_spawn(*is_close_on_exec);
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
IoctlCmd::FIOCLEX(_) => {
|
|
||||||
entry.set_close_on_spawn(true);
|
file_ref.ioctl(cmd.as_mut())?;
|
||||||
return Ok(0);
|
raw_cmd.copy_output_from_safe(cmd.as_ref());
|
||||||
}
|
Ok(0)
|
||||||
_ => return file_ref.ioctl(cmd),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -69,7 +69,29 @@ impl<'a> NonBuiltinIoctlCmd<'a> {
|
|||||||
pub fn arg_len(&self) -> usize {
|
pub fn arg_len(&self) -> usize {
|
||||||
self.cmd_num.arg_size()
|
self.cmd_num.arg_size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn execute(&self, host_fd: FileDesc) -> Result<()> {
|
||||||
|
let cmd_num = self.cmd_num().as_u32() as c_int;
|
||||||
|
let cmd_arg_ptr = self.arg_ptr() as *mut c_void;
|
||||||
|
|
||||||
|
let ret = try_libc!({
|
||||||
|
let mut retval: i32 = 0;
|
||||||
|
let status = occlum_ocall_ioctl(
|
||||||
|
&mut retval as *mut i32,
|
||||||
|
host_fd as i32,
|
||||||
|
cmd_num,
|
||||||
|
cmd_arg_ptr,
|
||||||
|
self.arg_len(),
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
retval
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoctlCmd for NonBuiltinIoctlCmd<'static> {}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct StructuredIoctlNum {
|
pub struct StructuredIoctlNum {
|
||||||
|
@ -14,8 +14,9 @@ pub use self::fspath::{get_abs_path_by_fd, FsPath, AT_FDCWD};
|
|||||||
pub use self::fsync::{do_fdatasync, do_fsync};
|
pub use self::fsync::{do_fdatasync, do_fsync};
|
||||||
pub use self::getdents::{do_getdents, do_getdents64};
|
pub use self::getdents::{do_getdents, do_getdents64};
|
||||||
pub use self::ioctl::{
|
pub use self::ioctl::{
|
||||||
do_ioctl, occlum_ocall_ioctl, BuiltinIoctlNum, IfConf, IoctlCmd, StructuredIoctlArgType,
|
do_ioctl, occlum_ocall_ioctl, BuiltinIoctlNum, GetIfConf, GetIfReqWithRawCmd, GetReadBufLen,
|
||||||
StructuredIoctlNum,
|
GetWinSize, IfConf, IoctlCmd, IoctlRawCmd, NonBuiltinIoctlCmd, SetNonBlocking, SetWinSize,
|
||||||
|
StructuredIoctlArgType, StructuredIoctlNum, TcGets, TcSets,
|
||||||
};
|
};
|
||||||
pub use self::link::{do_linkat, LinkFlags};
|
pub use self::link::{do_linkat, LinkFlags};
|
||||||
pub use self::lseek::do_lseek;
|
pub use self::lseek::do_lseek;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::fs::IoctlCmd;
|
||||||
use crate::net::PollEventFlags;
|
use crate::net::PollEventFlags;
|
||||||
use crate::process::do_getuid;
|
use crate::process::do_getuid;
|
||||||
use rcore_fs::vfs::FallocateMode;
|
use rcore_fs::vfs::FallocateMode;
|
||||||
@ -275,16 +276,13 @@ impl File for INodeFile {
|
|||||||
self.unlock_range_lock(&range_lock)
|
self.unlock_range_lock(&range_lock)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
match cmd {
|
match_ioctl_cmd_auto_error!(cmd, {
|
||||||
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
cmd : NonBuiltinIoctlCmd => {
|
||||||
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
self.inode.io_control(cmd.cmd_num().as_u32(), cmd.arg_ptr() as usize)?;
|
||||||
_ => {}
|
},
|
||||||
};
|
});
|
||||||
let cmd_num = cmd.cmd_num();
|
Ok(())
|
||||||
let cmd_argp = cmd.arg_ptr() as usize;
|
|
||||||
self.inode.io_control(cmd_num, cmd_argp)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_new(&self) -> IoEvents {
|
fn poll_new(&self) -> IoEvents {
|
||||||
|
@ -19,8 +19,9 @@ pub use self::events::{AtomicIoEvents, IoEvents, IoNotifier};
|
|||||||
pub use self::file::{File, FileRef};
|
pub use self::file::{File, FileRef};
|
||||||
pub use self::file_ops::{
|
pub use self::file_ops::{
|
||||||
occlum_ocall_ioctl, utimbuf_t, AccessMode, BuiltinIoctlNum, CreationFlags, FallocateFlags,
|
occlum_ocall_ioctl, utimbuf_t, AccessMode, BuiltinIoctlNum, CreationFlags, FallocateFlags,
|
||||||
FileMode, IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
|
FileMode, GetIfConf, GetIfReqWithRawCmd, GetReadBufLen, GetWinSize, IfConf, IoctlCmd,
|
||||||
STATUS_FLAGS_MASK,
|
IoctlRawCmd, NonBuiltinIoctlCmd, SetNonBlocking, SetWinSize, Stat, StatusFlags,
|
||||||
|
StructuredIoctlArgType, StructuredIoctlNum, TcGets, TcSets, STATUS_FLAGS_MASK,
|
||||||
};
|
};
|
||||||
pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier};
|
pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier};
|
||||||
pub use self::fs_ops::Statfs;
|
pub use self::fs_ops::Statfs;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use atomic::{Atomic, Ordering};
|
use atomic::{Atomic, Ordering};
|
||||||
|
use net::PollEventFlags;
|
||||||
|
|
||||||
use super::channel::{Channel, Consumer, Producer};
|
use super::channel::{Channel, Consumer, Producer};
|
||||||
use super::*;
|
use super::*;
|
||||||
use net::PollEventFlags;
|
|
||||||
|
use crate::fs::{GetReadBufLen, IoctlCmd};
|
||||||
|
|
||||||
// TODO: Add F_SETPIPE_SZ in fcntl to dynamically change the size of pipe
|
// TODO: Add F_SETPIPE_SZ in fcntl to dynamically change the size of pipe
|
||||||
// to improve memory efficiency. This value is got from /proc/sys/fs/pipe-max-size on linux.
|
// to improve memory efficiency. This value is got from /proc/sys/fs/pipe-max-size on linux.
|
||||||
@ -107,18 +109,14 @@ impl File for PipeReader {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
match cmd {
|
match_ioctl_cmd_auto_error!(cmd, {
|
||||||
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
cmd : GetReadBufLen => {
|
||||||
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
let read_buf_len = self.consumer.ready_len();
|
||||||
IoctlCmd::FIONREAD(arg) => {
|
cmd.set_output(read_buf_len as _);
|
||||||
let ready_len = self.get_ready_len().min(std::i32::MAX as usize) as i32;
|
},
|
||||||
**arg = ready_len;
|
});
|
||||||
return Ok(0);
|
Ok(())
|
||||||
}
|
|
||||||
_ => return_errno!(ENOSYS, "not supported"),
|
|
||||||
};
|
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,13 +207,9 @@ impl File for PipeWriter {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
match cmd {
|
match_ioctl_cmd_auto_error!(cmd, {});
|
||||||
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
Ok(())
|
||||||
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
|
||||||
_ => return_errno!(ENOSYS, "not supported"),
|
|
||||||
};
|
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ use core::cmp;
|
|||||||
use std::io::{BufReader, LineWriter};
|
use std::io::{BufReader, LineWriter};
|
||||||
use std::sync::SgxMutex;
|
use std::sync::SgxMutex;
|
||||||
|
|
||||||
|
use crate::fs::file_ops::{GetWinSize, SetWinSize, TcGets, TcSets};
|
||||||
|
use crate::fs::IoctlCmd;
|
||||||
|
|
||||||
macro_rules! try_libc_stdio {
|
macro_rules! try_libc_stdio {
|
||||||
($ret: expr) => {{
|
($ret: expr) => {{
|
||||||
let ret = unsafe { $ret };
|
let ret = unsafe { $ret };
|
||||||
@ -169,50 +172,6 @@ impl File for StdoutFile {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
|
||||||
let host_stdout_fd = self.host_fd() as i32;
|
|
||||||
let cmd_bits = cmd.cmd_num() as c_int;
|
|
||||||
|
|
||||||
// Handle special case for TCGETS/TCSETS which use different structures
|
|
||||||
// in linux kernel and libc
|
|
||||||
match cmd {
|
|
||||||
IoctlCmd::TCGETS(kernel_termios) => {
|
|
||||||
return kernel_termios.execute_tcgets(host_stdout_fd, cmd_bits);
|
|
||||||
}
|
|
||||||
IoctlCmd::TCSETS(kernel_termios) => {
|
|
||||||
return kernel_termios.execute_tcsets(host_stdout_fd, cmd_bits);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
let can_delegate_to_host = match cmd {
|
|
||||||
IoctlCmd::TIOCGWINSZ(_) => true,
|
|
||||||
IoctlCmd::TIOCSWINSZ(_) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if !can_delegate_to_host {
|
|
||||||
return_errno!(EINVAL, "unknown ioctl cmd for stdout");
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void;
|
|
||||||
let cmd_arg_len = cmd.arg_len();
|
|
||||||
let ret = try_libc!({
|
|
||||||
let mut retval: i32 = 0;
|
|
||||||
let status = occlum_ocall_ioctl(
|
|
||||||
&mut retval as *mut i32,
|
|
||||||
host_stdout_fd,
|
|
||||||
cmd_bits,
|
|
||||||
cmd_arg_ptr,
|
|
||||||
cmd_arg_len,
|
|
||||||
);
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
retval
|
|
||||||
});
|
|
||||||
cmd.validate_arg_and_ret_vals(ret)?;
|
|
||||||
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn status_flags(&self) -> Result<StatusFlags> {
|
fn status_flags(&self) -> Result<StatusFlags> {
|
||||||
let ret = try_libc!(libc::ocall::fcntl_arg0(
|
let ret = try_libc!(libc::ocall::fcntl_arg0(
|
||||||
self.host_fd() as i32,
|
self.host_fd() as i32,
|
||||||
@ -359,48 +318,8 @@ impl File for StdinFile {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
let host_stdin_fd = self.host_fd() as i32;
|
stdio_ioctl(cmd, self.host_fd())
|
||||||
let cmd_bits = cmd.cmd_num() as c_int;
|
|
||||||
|
|
||||||
// Handle special case for TCGETS/TCSETS which use different structures
|
|
||||||
// in linux kernel and libc
|
|
||||||
match cmd {
|
|
||||||
IoctlCmd::TCGETS(kernel_termios) => {
|
|
||||||
return kernel_termios.execute_tcgets(host_stdin_fd, cmd_bits);
|
|
||||||
}
|
|
||||||
IoctlCmd::TCSETS(kernel_termios) => {
|
|
||||||
return kernel_termios.execute_tcsets(host_stdin_fd, cmd_bits);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
let can_delegate_to_host = match cmd {
|
|
||||||
IoctlCmd::TIOCGWINSZ(_) => true,
|
|
||||||
IoctlCmd::TIOCSWINSZ(_) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if !can_delegate_to_host {
|
|
||||||
return_errno!(EINVAL, "unknown ioctl cmd for stdin");
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void;
|
|
||||||
let cmd_arg_len = cmd.arg_len();
|
|
||||||
let ret = try_libc!({
|
|
||||||
let mut retval: i32 = 0;
|
|
||||||
let status = occlum_ocall_ioctl(
|
|
||||||
&mut retval as *mut i32,
|
|
||||||
host_stdin_fd,
|
|
||||||
cmd_bits,
|
|
||||||
cmd_arg_ptr,
|
|
||||||
cmd_arg_len,
|
|
||||||
);
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
retval
|
|
||||||
});
|
|
||||||
cmd.validate_arg_and_ret_vals(ret)?;
|
|
||||||
|
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn status_flags(&self) -> Result<StatusFlags> {
|
fn status_flags(&self) -> Result<StatusFlags> {
|
||||||
@ -444,3 +363,22 @@ impl Debug for StdinFile {
|
|||||||
|
|
||||||
unsafe impl Send for StdinFile {}
|
unsafe impl Send for StdinFile {}
|
||||||
unsafe impl Sync for StdinFile {}
|
unsafe impl Sync for StdinFile {}
|
||||||
|
|
||||||
|
fn stdio_ioctl(cmd: &mut dyn IoctlCmd, host_fd: FileDesc) -> Result<()> {
|
||||||
|
debug!("stdio ioctl: cmd: {:?}", cmd);
|
||||||
|
match_ioctl_cmd_auto_error!(cmd, {
|
||||||
|
cmd : TcGets => {
|
||||||
|
cmd.execute(host_fd)?
|
||||||
|
},
|
||||||
|
cmd : TcSets => {
|
||||||
|
cmd.execute(host_fd)?
|
||||||
|
},
|
||||||
|
cmd : SetWinSize => {
|
||||||
|
cmd.execute(host_fd)?
|
||||||
|
},
|
||||||
|
cmd : GetWinSize => {
|
||||||
|
cmd.execute(host_fd)?
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -673,7 +673,7 @@ pub fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result<isize> {
|
|||||||
if argp.is_null() == false {
|
if argp.is_null() == false {
|
||||||
from_user::check_mut_ptr(argp)?;
|
from_user::check_mut_ptr(argp)?;
|
||||||
}
|
}
|
||||||
IoctlCmd::new(cmd, argp)?
|
IoctlRawCmd::new(cmd, argp)?
|
||||||
};
|
};
|
||||||
file_ops::do_ioctl(fd, &mut ioctl_cmd)?;
|
file_ops::do_ioctl(fd, &mut ioctl_cmd)?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
|
@ -115,11 +115,6 @@ impl File for TimerFile {
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement ioctl
|
|
||||||
// fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
|
||||||
// self.ioctl_impl(cmd)
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn access_mode(&self) -> Result<AccessMode> {
|
fn access_mode(&self) -> Result<AccessMode> {
|
||||||
Ok(AccessMode::O_RDWR)
|
Ok(AccessMode::O_RDWR)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user