Skip to content

Commit

Permalink
Merge branch 'advanced-redirects' into 'main'
Browse files Browse the repository at this point in the history
Advanced redirects

See merge request repositories/wasi_ext_lib!12
  • Loading branch information
GPlaczek committed Aug 4, 2023
2 parents 44ac505 + a565d86 commit d49a1d5
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 78 deletions.
68 changes: 45 additions & 23 deletions c_lib/wasi_ext_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,6 @@
#define SYSCALL_LENGTH 256
#define SYSCALL_ARGS_LENGTH 2048

JsonNode *json_mkredirect(struct Redirect redir) {
JsonNode *node = json_mkobject();
json_append_member(node, "fd", json_mknumber((double)redir.fd));
json_append_member(node, "path", json_mkstring(redir.path));
switch (redir.type) {
case READ:
json_append_member(node, "mode", json_mkstring("read"));
break;
case WRITE:
json_append_member(node, "mode", json_mkstring("write"));
break;
case APPEND:
json_append_member(node, "mode", json_mkstring("append"));
break;
}
return node;
}

int __syscall(const char *command, char *args, uint8_t *output_buf,
size_t output_buf_len) {
char *ptr;
Expand Down Expand Up @@ -212,11 +194,10 @@ int wasi_ext_spawn(const char *path, const char *const *args, size_t n_args,

json_append_member(root, "background", json_mkbool((bool)background));

JsonNode *_redirects = json_mkarray();
for (size_t i = 0; i < n_redirects; i++) {
json_append_element(_redirects, json_mkredirect(redirects[i]));
}
json_append_member(root, "redirects", _redirects);
json_append_member(root, "redirects_ptr",
json_mknumber((double)((size_t)redirects)));

json_append_member(root, "n_redirects", json_mknumber((double)n_redirects));

char *call_args = json_stringify(0, root, " ");
json_delete(root);
Expand Down Expand Up @@ -262,3 +243,44 @@ int wasi_ext_ioctl(int fd, unsigned int cmd, void *arg) {

return -err;
}

int wasi_ext_fcntl(int fd, enum FcntlCommand cmd, void *arg) {
__wasi_errno_t err;
switch (cmd) {
case F_MVFD: {
int min_fd = *((int *)arg);
__wasi_fdstat_t stat;

for (; min_fd < _MAX_FD_NUM; ++min_fd) {
err = __wasi_fd_fdstat_get(min_fd, &stat);

if (__WASI_ERRNO_BADF == err) {
break;
} else if (__WASI_ERRNO_SUCCESS != err) {
return -err;
}
}

if (min_fd >= _MAX_FD_NUM) {
return __WASI_ERRNO_MFILE;
}

// We assume fd_renumber behaves like dup2
err = __wasi_fd_renumber(fd, min_fd);
if (__WASI_ERRNO_SUCCESS != err) {
return -err;
}

err = __wasi_fd_close(fd);
if (__WASI_ERRNO_SUCCESS != err) {
return -err;
}
break;
}
default: {
return -EINVAL;
}
}

return 0;
}
35 changes: 31 additions & 4 deletions c_lib/wasi_ext_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,46 @@
#define _IOGM(mn) ((mn & _IOM_MASK) >> _IOM_OFF)
#define _IOGF(mn) ((mn & _IOF_MASK) >> _IOF_OFF)

#define _MAX_FD_NUM 1024

#include <stdlib.h>

// Ioctl magic numbers
const unsigned int TIOCGWINSZ = _IOR(1, 0, 8);
const unsigned int TIOCSRAW = _IOW(1, 1, 4);
const unsigned int TIOCSECHO = _IOW(1, 2, 4);

enum RedirectType { READ, WRITE, APPEND };
// Fnctl commands
enum FcntlCommand { F_MVFD };

const int STDIN = 0;
const int STDOUT = 1;

enum RedirectType {
READ,
WRITE,
APPEND,
READWRITE,
PIPEIN,
PIPEOUT,
DUPLICATE,
CLOSE
};

struct Redirect {
int fd;
const char *path;
union Data {
struct Path {
const char *path_str;
size_t path_len;
} path;

int fd_src;
} data;

int fd_dst;
enum RedirectType type;
};

struct Env {
const char *attrib;
const char *val;
Expand Down Expand Up @@ -74,8 +100,9 @@ int wasi_ext_attach_sigint(int32_t);
int wasi_ext_clean_inodes();
int wasi_ext_spawn(const char *, const char *const *, size_t,
const struct Env *, size_t, int, const struct Redirect *,
size_t n_redirects, int *);
size_t, int *);
int wasi_ext_kill(int, int);
int wasi_ext_ioctl(int, unsigned int, void *);
int wasi_ext_fcntl(int, enum FcntlCommand, void *);

#endif
147 changes: 96 additions & 51 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ use std::collections::HashMap;
use std::convert::AsRef;
use std::convert::From;
use std::env;
use std::ffi::{c_uint, c_void, CString};
use std::ffi::{c_int, c_uint, c_void, CString};
use std::fs;
use std::mem;
use std::os::fd::RawFd;
use std::os::wasi::ffi::OsStrExt;
use std::os::wasi::prelude::RawFd;
use std::path::Path;
use std::ptr;
use std::str;

mod wasi_ext_lib_generated;
use wasi_ext_lib_generated::{
RedirectType_APPEND, RedirectType_CLOSE, RedirectType_DUPLICATE, RedirectType_PIPEIN,
RedirectType_PIPEOUT, RedirectType_READ, RedirectType_READWRITE, RedirectType_WRITE,
Redirect_Data, Redirect_Data_Path, STDIN, STDOUT,
};

#[cfg(feature = "hterm")]
pub use wasi_ext_lib_generated::{
Expand All @@ -30,10 +36,16 @@ pub use wasi::SIGNAL_KILL;
type ExitCode = i32;
type Pid = i32;

pub enum Redirect<'a> {
Read((wasi::Fd, &'a str)),
Write((wasi::Fd, &'a str)),
Append((wasi::Fd, &'a str)),
#[derive(Debug)]
pub enum Redirect {
Read(wasi::Fd, String),
Write(wasi::Fd, String),
Append(wasi::Fd, String),
ReadWrite(wasi::Fd, String),
PipeIn(wasi::Fd),
PipeOut(wasi::Fd),
Duplicate { fd_src: wasi::Fd, fd_dst: wasi::Fd },
Close(wasi::Fd),
}

#[repr(u32)]
Expand All @@ -43,44 +55,65 @@ pub enum IoctlNum {
SetEcho = wasi_ext_lib_generated::TIOCSECHO,
}

enum CStringRedirect {
Read((wasi::Fd, CString)),
Write((wasi::Fd, CString)),
Append((wasi::Fd, CString)),
}

impl From<Redirect<'_>> for CStringRedirect {
fn from(redirect: Redirect) -> Self {
impl From<&Redirect> for wasi_ext_lib_generated::Redirect {
fn from(redirect: &Redirect) -> Self {
match redirect {
Redirect::Read((fd, path)) => CStringRedirect::Read((fd, CString::new(path).unwrap())),
Redirect::Write((fd, path)) => {
CStringRedirect::Write((fd, CString::new(path).unwrap()))
}
Redirect::Append((fd, path)) => {
CStringRedirect::Append((fd, CString::new(path).unwrap()))
Redirect::Read(fd, path)
| Redirect::Write(fd, path)
| Redirect::Append(fd, path)
| Redirect::ReadWrite(fd, path) => {
let tag = match redirect {
Redirect::Read(_, _) => RedirectType_READ,
Redirect::Write(_, _) => RedirectType_WRITE,
Redirect::Append(_, _) => RedirectType_APPEND,
Redirect::ReadWrite(_, _) => RedirectType_READWRITE,
_ => unreachable!(),
};

wasi_ext_lib_generated::Redirect {
data: Redirect_Data {
path: Redirect_Data_Path {
path_str: path.as_ptr() as *const i8,
path_len: path.len(),
},
},
fd_dst: *fd as i32,
type_: tag,
}
}
Redirect::PipeIn(fd_src) => wasi_ext_lib_generated::Redirect {
data: Redirect_Data {
fd_src: *fd_src as i32,
},
fd_dst: STDIN,
type_: RedirectType_PIPEIN,
},
Redirect::PipeOut(fd_src) => wasi_ext_lib_generated::Redirect {
data: Redirect_Data {
fd_src: *fd_src as i32,
},
fd_dst: STDOUT,
type_: RedirectType_PIPEOUT,
},
Redirect::Duplicate { fd_src, fd_dst } => wasi_ext_lib_generated::Redirect {
data: Redirect_Data {
fd_src: *fd_src as i32,
},
fd_dst: *fd_dst as i32,
type_: RedirectType_DUPLICATE,
},
Redirect::Close(fd_dst) => wasi_ext_lib_generated::Redirect {
data: unsafe { mem::zeroed() }, // ignore field in kernel
fd_dst: *fd_dst as i32,
type_: RedirectType_CLOSE,
},
}
}
}

unsafe fn get_c_redirect(r: &CStringRedirect) -> wasi_ext_lib_generated::Redirect {
match r {
CStringRedirect::Read((fd, path)) => wasi_ext_lib_generated::Redirect {
type_: wasi_ext_lib_generated::RedirectType_READ,
path: path.as_c_str().as_ptr(),
fd: *fd as i32,
},
CStringRedirect::Write((fd, path)) => wasi_ext_lib_generated::Redirect {
type_: wasi_ext_lib_generated::RedirectType_WRITE,
path: path.as_c_str().as_ptr(),
fd: *fd as i32,
},
CStringRedirect::Append((fd, path)) => wasi_ext_lib_generated::Redirect {
type_: wasi_ext_lib_generated::RedirectType_APPEND,
path: path.as_c_str().as_ptr(),
fd: *fd as i32,
},
}
pub enum FcntlCommand {
// like F_DUPFD but it move fd insted of duplicating
F_MVFD { min_fd_num: wasi::Fd },
}

pub fn chdir<P: AsRef<Path>>(path: P) -> Result<(), ExitCode> {
Expand Down Expand Up @@ -205,7 +238,7 @@ pub fn spawn(
args: &[&str],
env: &HashMap<String, String>,
background: bool,
redirects: Vec<Redirect>,
redirects: &[Redirect],
) -> Result<(ExitCode, Pid), ExitCode> {
let mut child_pid: Pid = -1;
let syscall_result = unsafe {
Expand All @@ -223,12 +256,11 @@ pub fn spawn(
)
})
.collect::<Vec<(CString, CString)>>();

let cstring_redirects = redirects
.into_iter()
.map(CStringRedirect::from)
.collect::<Vec<CStringRedirect>>();

let redirects_len = redirects.len();
let redirects_vec = redirects
.iter()
.map(wasi_ext_lib_generated::Redirect::from)
.collect::<Vec<wasi_ext_lib_generated::Redirect>>();
wasi_ext_lib_generated::wasi_ext_spawn(
CString::new(path).unwrap().as_c_str().as_ptr(),
cstring_args
Expand All @@ -247,12 +279,8 @@ pub fn spawn(
.as_ptr(),
env.len(),
background as i32,
cstring_redirects
.iter()
.map(|red| get_c_redirect(red))
.collect::<Vec<wasi_ext_lib_generated::Redirect>>()
.as_ptr(),
cstring_redirects.len(),
redirects_vec.as_ptr(),
redirects_len,
&mut child_pid,
)
};
Expand Down Expand Up @@ -291,3 +319,20 @@ pub fn ioctl<T>(fd: RawFd, command: IoctlNum, arg: Option<&mut T>) -> Result<(),
Ok(())
}
}
pub fn fcntl(fd: wasi::Fd, cmd: FcntlCommand) -> Result<i32, ExitCode> {
let result = match cmd {
FcntlCommand::F_MVFD { min_fd_num } => unsafe {
wasi_ext_lib_generated::wasi_ext_fcntl(
fd as c_int,
wasi_ext_lib_generated::FcntlCommand_F_MVFD,
min_fd_num as *mut c_void,
)
},
};

if result < 0 {
Err(-result)
} else {
Ok(result)
}
}

0 comments on commit d49a1d5

Please sign in to comment.