wasmer_wasix/os/command/
mod.rs1pub mod builtins;
2
3use std::{collections::HashMap, sync::Arc};
4
5use virtual_mio::block_on;
6use wasmer::FunctionEnvMut;
7use wasmer_wasix_types::wasi::Errno;
8
9use crate::{Runtime, SpawnError, WasiEnv, syscalls::stderr_write};
10
11use super::task::{OwnedTaskStatus, TaskJoinHandle, TaskStatus};
12
13type BuiltinCommandHandler = dyn for<'a> Fn(
14 &FunctionEnvMut<'a, WasiEnv>,
15 &str,
16 &mut Option<WasiEnv>,
17 ) -> Result<TaskJoinHandle, SpawnError>
18 + Send
19 + Sync
20 + 'static;
21
22#[derive(Clone)]
23pub struct BuiltinCommand {
24 name: String,
25 handler: Arc<BuiltinCommandHandler>,
26}
27
28impl std::fmt::Debug for BuiltinCommand {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.debug_struct("BuiltinCommand")
31 .field("name", &self.name)
32 .finish()
33 }
34}
35
36impl BuiltinCommand {
37 pub fn new<Name, Handler>(name: Name, handler: Handler) -> Self
38 where
39 Name: Into<String>,
40 Handler: for<'a> Fn(
41 &FunctionEnvMut<'a, WasiEnv>,
42 &str,
43 &mut Option<WasiEnv>,
44 ) -> Result<TaskJoinHandle, SpawnError>
45 + Send
46 + Sync
47 + 'static,
48 {
49 Self {
50 name: name.into(),
51 handler: Arc::new(handler),
52 }
53 }
54}
55
56impl VirtualCommand for BuiltinCommand {
57 fn name(&self) -> &str {
58 self.name.as_str()
59 }
60
61 fn as_any(&self) -> &dyn std::any::Any {
62 self
63 }
64
65 fn exec(
66 &self,
67 parent_ctx: &FunctionEnvMut<'_, WasiEnv>,
68 path: &str,
69 config: &mut Option<WasiEnv>,
70 ) -> Result<TaskJoinHandle, SpawnError> {
71 (self.handler)(parent_ctx, path, config)
72 }
73}
74
75pub trait VirtualCommand
77where
78 Self: std::fmt::Debug,
79{
80 fn name(&self) -> &str;
82
83 fn as_any(&self) -> &dyn std::any::Any;
85
86 fn exec(
88 &self,
89 parent_ctx: &FunctionEnvMut<'_, WasiEnv>,
90 path: &str,
91 config: &mut Option<WasiEnv>,
92 ) -> Result<TaskJoinHandle, SpawnError>;
93}
94
95#[derive(Debug, Clone)]
96pub struct Commands {
97 commands: HashMap<String, Arc<dyn VirtualCommand + Send + Sync + 'static>>,
98}
99
100impl Commands {
101 fn new() -> Self {
102 Self {
103 commands: HashMap::new(),
104 }
105 }
106
107 pub fn new_with_builtins(runtime: Arc<dyn Runtime + Send + Sync + 'static>) -> Self {
109 let mut cmd = Self::new();
110 let cmd_wasmer = builtins::cmd_wasmer::CmdWasmer::new(runtime.clone());
111 cmd.register_command(cmd_wasmer);
112
113 cmd
114 }
115
116 pub fn register_command<C: VirtualCommand + Send + Sync + 'static>(&mut self, cmd: C) {
120 self.register_command_shared(Arc::new(cmd));
121 }
122
123 pub fn register_command_with_path<C: VirtualCommand + Send + Sync + 'static>(
125 &mut self,
126 cmd: C,
127 path: String,
128 ) {
129 self.register_command_with_path_shared(Arc::new(cmd), path);
130 }
131
132 pub(crate) fn register_command_shared(
134 &mut self,
135 cmd: Arc<dyn VirtualCommand + Send + Sync + 'static>,
136 ) {
137 let path = format!("/bin/{}", cmd.name());
138 self.register_command_with_path_shared(cmd, path);
139 }
140
141 pub(crate) fn register_command_with_path_shared(
143 &mut self,
144 cmd: Arc<dyn VirtualCommand + Send + Sync + 'static>,
145 path: String,
146 ) {
147 self.commands.insert(path, cmd);
148 }
149
150 pub fn clear(&mut self) {
152 self.commands.clear();
153 }
154
155 pub fn exists(&self, path: &str) -> bool {
157 let name = path.to_string();
158 self.commands.contains_key(&name)
159 }
160
161 pub fn get(&self, path: &str) -> Option<&Arc<dyn VirtualCommand + Send + Sync + 'static>> {
163 self.commands.get(path)
164 }
165
166 pub fn exec(
168 &self,
169 parent_ctx: &FunctionEnvMut<'_, WasiEnv>,
170 path: &str,
171 builder: &mut Option<WasiEnv>,
172 ) -> Result<TaskJoinHandle, SpawnError> {
173 let path = path.to_string();
174 if let Some(cmd) = self.commands.get(&path) {
175 cmd.exec(parent_ctx, path.as_str(), builder)
176 } else {
177 unsafe {
178 block_on(stderr_write(
179 parent_ctx,
180 format!("wasm command unknown - {path}\r\n").as_bytes(),
181 ))
182 }
183 .ok();
184
185 let res = OwnedTaskStatus::new(TaskStatus::Finished(Ok(Errno::Noent.into())));
186 Ok(res.handle())
187 }
188 }
189}