wasi_cap_std_sync/
lib.rs

1//! The `wasi-cap-std-sync` crate provides impl of `WasiFile` and `WasiDir` in
2//! terms of `cap_std::fs::{File, Dir}`. These types provide sandboxed access
3//! to the local filesystem on both Unix and Windows.
4//!
5//! All syscalls are hidden behind the `cap-std` hierarchy, with the lone
6//! exception of the `sched` implementation, which is provided for both unix
7//! and windows in separate modules.
8//!
9//! Any `wasi_common::{WasiCtx, WasiCtxBuilder}` is interoperable with the
10//! `wasi-cap-std-sync` crate. However, for convenience, `wasi-cap-std-sync`
11//! provides its own `WasiCtxBuilder` that hooks up to all of the crate's
12//! components, i.e. it fills in all of the arguments to
13//! `WasiCtx::builder(...)`, presents `preopen_dir` in terms of
14//! `cap_std::fs::Dir`, and provides convenience methods for inheriting the
15//! parent process's stdio, args, and env.
16//!
17//! For the convenience of consumers, `cap_std::fs::Dir` is re-exported from
18//! this crate. This saves consumers tracking an additional dep on the exact
19//! version of cap_std used by this crate, if they want to avoid it.
20//!
21//! The only place we expect to run into long-term compatibility issues
22//! between `wasi-cap-std-sync` and the other impl crates that will come later
23//! is in the `Sched` abstraction. Once we can build an async scheduler based
24//! on Rust `Future`s, async impls will be able to interoperate, but the
25//! synchronous scheduler depends on downcasting the `WasiFile` type down to
26//! concrete types it knows about (which in turn impl `AsFd` for passing to
27//! unix `poll`, or the analogous traits on windows).
28//!
29//! Why is this impl suffixed with `-sync`? Because `async` is coming soon!
30//! The async impl may end up depending on tokio or other relatively heavy
31//! deps, so we will retain a sync implementation so that wasi-common users
32//! have an option of not pulling in an async runtime.
33
34#![cfg_attr(io_lifetimes_use_std, feature(io_safety))]
35
36pub mod clocks;
37pub mod dir;
38pub mod file;
39pub mod net;
40pub mod sched;
41pub mod stdio;
42
43pub use cap_std::ambient_authority;
44pub use cap_std::fs::Dir;
45pub use cap_std::net::TcpListener;
46pub use clocks::clocks_ctx;
47pub use sched::sched_ctx;
48
49use crate::net::Socket;
50use cap_rand::{Rng, RngCore, SeedableRng};
51use std::mem;
52use std::path::Path;
53use wasi_common::{file::FileAccessMode, table::Table, Error, WasiCtx, WasiFile};
54
55pub struct WasiCtxBuilder {
56    ctx: WasiCtx,
57    built: bool,
58}
59
60impl WasiCtxBuilder {
61    pub fn new() -> Self {
62        WasiCtxBuilder {
63            ctx: WasiCtx::new(random_ctx(), clocks_ctx(), sched_ctx(), Table::new()),
64            built: false,
65        }
66    }
67    pub fn env(
68        &mut self,
69        var: &str,
70        value: &str,
71    ) -> Result<&mut Self, wasi_common::StringArrayError> {
72        self.ctx.push_env(var, value)?;
73        Ok(self)
74    }
75    pub fn envs(
76        &mut self,
77        env: &[(String, String)],
78    ) -> Result<&mut Self, wasi_common::StringArrayError> {
79        for (k, v) in env {
80            self.ctx.push_env(k, v)?;
81        }
82        Ok(self)
83    }
84    pub fn inherit_env(&mut self) -> Result<&mut Self, wasi_common::StringArrayError> {
85        for (key, value) in std::env::vars() {
86            self.ctx.push_env(&key, &value)?;
87        }
88        Ok(self)
89    }
90    pub fn arg(&mut self, arg: &str) -> Result<&mut Self, wasi_common::StringArrayError> {
91        self.ctx.push_arg(arg)?;
92        Ok(self)
93    }
94    pub fn args(&mut self, arg: &[String]) -> Result<&mut Self, wasi_common::StringArrayError> {
95        for a in arg {
96            self.ctx.push_arg(&a)?;
97        }
98        Ok(self)
99    }
100    pub fn inherit_args(&mut self) -> Result<&mut Self, wasi_common::StringArrayError> {
101        for arg in std::env::args() {
102            self.ctx.push_arg(&arg)?;
103        }
104        Ok(self)
105    }
106    pub fn stdin(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
107        self.ctx.set_stdin(f);
108        self
109    }
110    pub fn stdout(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
111        self.ctx.set_stdout(f);
112        self
113    }
114    pub fn stderr(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
115        self.ctx.set_stderr(f);
116        self
117    }
118    pub fn inherit_stdin(&mut self) -> &mut Self {
119        self.stdin(Box::new(crate::stdio::stdin()))
120    }
121    pub fn inherit_stdout(&mut self) -> &mut Self {
122        self.stdout(Box::new(crate::stdio::stdout()))
123    }
124    pub fn inherit_stderr(&mut self) -> &mut Self {
125        self.stderr(Box::new(crate::stdio::stderr()))
126    }
127    pub fn inherit_stdio(&mut self) -> &mut Self {
128        self.inherit_stdin().inherit_stdout().inherit_stderr()
129    }
130    pub fn preopened_dir(
131        &mut self,
132        dir: Dir,
133        guest_path: impl AsRef<Path>,
134    ) -> Result<&mut Self, Error> {
135        let dir = Box::new(crate::dir::Dir::from_cap_std(dir));
136        self.ctx.push_preopened_dir(dir, guest_path)?;
137        Ok(self)
138    }
139    pub fn preopened_socket(
140        &mut self,
141        fd: u32,
142        socket: impl Into<Socket>,
143    ) -> Result<&mut Self, Error> {
144        let socket: Socket = socket.into();
145        let file: Box<dyn WasiFile> = socket.into();
146        self.ctx
147            .insert_file(fd, file, FileAccessMode::READ | FileAccessMode::WRITE);
148        Ok(self)
149    }
150    pub fn build(&mut self) -> WasiCtx {
151        assert!(!self.built);
152        let WasiCtxBuilder { ctx, .. } = mem::replace(self, Self::new());
153        self.built = true;
154        ctx
155    }
156}
157
158pub fn random_ctx() -> Box<dyn RngCore + Send + Sync> {
159    let mut rng = cap_rand::thread_rng(cap_rand::ambient_authority());
160    Box::new(cap_rand::rngs::StdRng::from_seed(rng.gen()))
161}