wasmer_wasix/os/command/
mod.rs1pub mod builtins;
2
3use std::{collections::HashMap, sync::Arc};
4
5use wasmer::FunctionEnvMut;
6use wasmer_wasix_types::wasi::Errno;
7
8use crate::{
9 Runtime, SpawnError, WasiEnv, runtime::task_manager::InlineWaker, syscalls::stderr_write,
10};
11
12use super::task::{OwnedTaskStatus, TaskJoinHandle, TaskStatus};
13
14pub trait VirtualCommand
16where
17 Self: std::fmt::Debug,
18{
19 fn name(&self) -> &str;
21
22 fn as_any(&self) -> &dyn std::any::Any;
24
25 fn exec(
27 &self,
28 parent_ctx: &FunctionEnvMut<'_, WasiEnv>,
29 path: &str,
30 config: &mut Option<WasiEnv>,
31 ) -> Result<TaskJoinHandle, SpawnError>;
32}
33
34#[derive(Debug, Clone)]
35pub struct Commands {
36 commands: HashMap<String, Arc<dyn VirtualCommand + Send + Sync + 'static>>,
37}
38
39impl Commands {
40 fn new() -> Self {
41 Self {
42 commands: HashMap::new(),
43 }
44 }
45
46 pub fn new_with_builtins(runtime: Arc<dyn Runtime + Send + Sync + 'static>) -> Self {
48 let mut cmd = Self::new();
49 let cmd_wasmer = builtins::cmd_wasmer::CmdWasmer::new(runtime.clone());
50 cmd.register_command(cmd_wasmer);
51
52 cmd
53 }
54
55 pub fn register_command<C: VirtualCommand + Send + Sync + 'static>(&mut self, cmd: C) {
59 let path = format!("/bin/{}", cmd.name());
60 self.register_command_with_path(cmd, path);
61 }
62
63 pub fn register_command_with_path<C: VirtualCommand + Send + Sync + 'static>(
65 &mut self,
66 cmd: C,
67 path: String,
68 ) {
69 self.commands.insert(path, Arc::new(cmd));
70 }
71
72 pub fn exists(&self, path: &str) -> bool {
74 let name = path.to_string();
75 self.commands.contains_key(&name)
76 }
77
78 pub fn get(&self, path: &str) -> Option<&Arc<dyn VirtualCommand + Send + Sync + 'static>> {
80 self.commands.get(path)
81 }
82
83 pub fn exec(
85 &self,
86 parent_ctx: &FunctionEnvMut<'_, WasiEnv>,
87 path: &str,
88 builder: &mut Option<WasiEnv>,
89 ) -> Result<TaskJoinHandle, SpawnError> {
90 let path = path.to_string();
91 if let Some(cmd) = self.commands.get(&path) {
92 cmd.exec(parent_ctx, path.as_str(), builder)
93 } else {
94 unsafe {
95 InlineWaker::block_on(stderr_write(
96 parent_ctx,
97 format!("wasm command unknown - {path}\r\n").as_bytes(),
98 ))
99 }
100 .ok();
101
102 let res = OwnedTaskStatus::new(TaskStatus::Finished(Ok(Errno::Noent.into())));
103 Ok(res.handle())
104 }
105 }
106}