//! Runs the shell component against one virtual world root for the S2 experiment. mod process; use sausage_vfs::{ Host, Mounts, Process, adapter::{self, Adapter, View}, }; use std::sync::Arc; use wasmtime::{ Engine, Store, component::{Component, Linker, ResourceTable}, }; use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiCtxView, WasiView}; struct State { wasi: WasiCtx, table: ResourceTable, fs: Adapter, runtime: Arc, children: Vec, } impl WasiView for State { fn ctx(&mut self) -> WasiCtxView<'_> { WasiCtxView { ctx: &mut self.wasi, table: &mut self.table, } } } #[tokio::main] async fn main() -> anyhow::Result<()> { let args: Vec = std::env::args().collect(); anyhow::ensure!( args.len() == 5 && args[3] == "-c", "usage: s2-shell WORLD SHELL.wasm -c SCRIPT" ); let mut config = wasmtime::Config::new(); let mut cache = wasmtime::CacheConfig::new(); cache.with_directory("/tmp/s2-shell/cache"); config.cache(Some(wasmtime::Cache::new(cache)?)); let engine = Engine::new(&config)?; let component = Component::from_file(&engine, &args[2])?; let runtime = Arc::new(process::Runtime { engine: engine.clone(), utility: Component::from_file(&engine, std::path::Path::new(&args[1]).join("bin/cat"))?, world: args[1].clone().into(), }); let mut mounts = Mounts::default(); mounts.mount( "/", Arc::new(Host::new(&args[1], Process::default())?), false, ); let mut linker = Linker::new(&engine); wasmtime_wasi::p2::add_to_linker_async(&mut linker)?; adapter::add_to_linker(&mut linker, |s: &mut State| View { adapter: &mut s.fs, table: &mut s.table, })?; process::add(&mut linker)?; let mut wasi = WasiCtxBuilder::new(); wasi.inherit_stdio() .args(&["sh", "--noprofile", "--norc", "-c", &args[4]]) .env("PATH", "/bin") .env("HOME", "/") .env("PWD", "/") .initial_cwd("/"); let mut store = Store::new( &engine, State { wasi: wasi.build(), table: ResourceTable::new(), fs: Adapter::new(mounts), runtime, children: Vec::new(), }, ); let command = wasmtime_wasi::p2::bindings::Command::instantiate_async(&mut store, &component, &linker) .await?; let code = match command.wasi_cli_run().call_run(&mut store).await { Ok(Ok(())) => 0, Ok(Err(())) => 1, Err(error) => match error.downcast_ref::() { Some(exit) => exit.0, None => return Err(error.into()), }, }; std::process::exit(code); }