feat(plugin): add exec_cmd helper for executing command in host
Signed-off-by: Tw <wei.tan@intel.com> Signed-off-by: Tw <tw19881113@gmail.com>
This commit is contained in:
parent
6d0c5a56f5
commit
19b3f8366f
12 changed files with 99 additions and 23 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -325,10 +325,15 @@ impl Tab {
|
||||||
if let Some(Run::Plugin(Some(plugin))) = &layout.run {
|
if let Some(Run::Plugin(Some(plugin))) = &layout.run {
|
||||||
let (pid_tx, pid_rx) = channel();
|
let (pid_tx, pid_rx) = channel();
|
||||||
self.senders
|
self.senders
|
||||||
.send_to_plugin(PluginInstruction::Load(pid_tx, plugin.clone(), tab_index))
|
.send_to_plugin(PluginInstruction::Load(
|
||||||
|
pid_tx,
|
||||||
|
plugin.path.clone(),
|
||||||
|
tab_index,
|
||||||
|
plugin._allow_exec_host_cmd,
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let pid = pid_rx.recv().unwrap();
|
let pid = pid_rx.recv().unwrap();
|
||||||
let title = String::from(plugin.as_path().as_os_str().to_string_lossy());
|
let title = String::from(plugin.path.as_path().as_os_str().to_string_lossy());
|
||||||
let mut new_plugin = PluginPane::new(
|
let mut new_plugin = PluginPane::new(
|
||||||
pid,
|
pid,
|
||||||
*position_and_size,
|
*position_and_size,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use log::info;
|
use log::{info, warn};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
@ -28,7 +28,7 @@ use zellij_utils::{input::command::TerminalAction, serde, zellij_tile};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) enum PluginInstruction {
|
pub(crate) enum PluginInstruction {
|
||||||
Load(Sender<u32>, PathBuf, usize), // tx_pid, path_of_plugin , tab_index
|
Load(Sender<u32>, PathBuf, usize, bool), // tx_pid, path_of_plugin , tab_index, allow_exec_host_cmd
|
||||||
Update(Option<u32>, Event), // Focused plugin / broadcast, event data
|
Update(Option<u32>, Event), // Focused plugin / broadcast, event data
|
||||||
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
||||||
Unload(u32),
|
Unload(u32),
|
||||||
|
|
@ -54,6 +54,8 @@ pub(crate) struct PluginEnv {
|
||||||
pub senders: ThreadSenders,
|
pub senders: ThreadSenders,
|
||||||
pub wasi_env: WasiEnv,
|
pub wasi_env: WasiEnv,
|
||||||
pub subscriptions: Arc<Mutex<HashSet<EventType>>>,
|
pub subscriptions: Arc<Mutex<HashSet<EventType>>>,
|
||||||
|
// FIXME: Once permission system is ready, this could be removed
|
||||||
|
pub _allow_exec_host_cmd: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread main --------------------------------------------------------------------------------------------------------
|
// Thread main --------------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -65,7 +67,7 @@ pub(crate) fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_d
|
||||||
let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");
|
let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");
|
||||||
err_ctx.add_call(ContextType::Plugin((&event).into()));
|
err_ctx.add_call(ContextType::Plugin((&event).into()));
|
||||||
match event {
|
match event {
|
||||||
PluginInstruction::Load(pid_tx, path, tab_index) => {
|
PluginInstruction::Load(pid_tx, path, tab_index, _allow_exec_host_cmd) => {
|
||||||
let plugin_dir = data_dir.join("plugins/");
|
let plugin_dir = data_dir.join("plugins/");
|
||||||
let wasm_bytes = fs::read(&path)
|
let wasm_bytes = fs::read(&path)
|
||||||
.or_else(|_| fs::read(&path.with_extension("wasm")))
|
.or_else(|_| fs::read(&path.with_extension("wasm")))
|
||||||
|
|
@ -99,12 +101,17 @@ pub(crate) fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_d
|
||||||
|
|
||||||
let wasi = wasi_env.import_object(&module).unwrap();
|
let wasi = wasi_env.import_object(&module).unwrap();
|
||||||
|
|
||||||
|
if _allow_exec_host_cmd {
|
||||||
|
info!("Plugin({:?}) is able to run any host command, this may lead to some security issues!", path);
|
||||||
|
}
|
||||||
|
|
||||||
let plugin_env = PluginEnv {
|
let plugin_env = PluginEnv {
|
||||||
plugin_id,
|
plugin_id,
|
||||||
tab_index,
|
tab_index,
|
||||||
senders: bus.senders.clone(),
|
senders: bus.senders.clone(),
|
||||||
wasi_env,
|
wasi_env,
|
||||||
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
||||||
|
_allow_exec_host_cmd,
|
||||||
};
|
};
|
||||||
|
|
||||||
let zellij = zellij_exports(&store, &plugin_env);
|
let zellij = zellij_exports(&store, &plugin_env);
|
||||||
|
|
@ -174,6 +181,7 @@ pub(crate) fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObj
|
||||||
host_get_plugin_ids,
|
host_get_plugin_ids,
|
||||||
host_open_file,
|
host_open_file,
|
||||||
host_set_timeout,
|
host_set_timeout,
|
||||||
|
host_exec_cmd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,6 +256,24 @@ fn host_set_timeout(plugin_env: &PluginEnv, secs: f64) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn host_exec_cmd(plugin_env: &PluginEnv) {
|
||||||
|
let mut cmdline: Vec<String> = wasi_read_object(&plugin_env.wasi_env);
|
||||||
|
let command = cmdline.remove(0);
|
||||||
|
|
||||||
|
// Bail out if we're forbidden to run command
|
||||||
|
if !plugin_env._allow_exec_host_cmd {
|
||||||
|
warn!("This plugin isn't allow to run command in host side, skip running this command: '{cmd} {args}'.",
|
||||||
|
cmd = command, args = cmdline.join(" "));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here, we don't wait the command to finish
|
||||||
|
process::Command::new(command)
|
||||||
|
.args(cmdline)
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// Helper Functions ---------------------------------------------------------------------------------------------------
|
// Helper Functions ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
pub fn wasi_read_string(wasi_env: &WasiEnv) -> String {
|
pub fn wasi_read_string(wasi_env: &WasiEnv) -> String {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,10 @@ pub fn open_file(path: &Path) {
|
||||||
pub fn set_timeout(secs: f64) {
|
pub fn set_timeout(secs: f64) {
|
||||||
unsafe { host_set_timeout(secs) };
|
unsafe { host_set_timeout(secs) };
|
||||||
}
|
}
|
||||||
|
pub fn exec_cmd(cmd: &[&str]) {
|
||||||
|
object_to_stdout(&cmd);
|
||||||
|
unsafe { host_exec_cmd() };
|
||||||
|
}
|
||||||
|
|
||||||
// Internal Functions
|
// Internal Functions
|
||||||
|
|
||||||
|
|
@ -60,4 +64,5 @@ extern "C" {
|
||||||
fn host_get_plugin_ids();
|
fn host_get_plugin_ids();
|
||||||
fn host_open_file();
|
fn host_open_file();
|
||||||
fn host_set_timeout(secs: f64);
|
fn host_set_timeout(secs: f64);
|
||||||
|
fn host_exec_cmd();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ template:
|
||||||
split_size:
|
split_size:
|
||||||
Fixed: 1
|
Fixed: 1
|
||||||
run:
|
run:
|
||||||
plugin: tab-bar
|
plugin:
|
||||||
|
path: tab-bar
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
body: true
|
body: true
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
|
|
@ -15,6 +16,7 @@ template:
|
||||||
split_size:
|
split_size:
|
||||||
Fixed: 2
|
Fixed: 2
|
||||||
run:
|
run:
|
||||||
plugin: status-bar
|
plugin:
|
||||||
|
path: status-bar
|
||||||
tabs:
|
tabs:
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ template:
|
||||||
split_size:
|
split_size:
|
||||||
Fixed: 1
|
Fixed: 1
|
||||||
run:
|
run:
|
||||||
plugin: tab-bar
|
plugin:
|
||||||
|
path: tab-bar
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
body: true
|
body: true
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ template:
|
||||||
split_size:
|
split_size:
|
||||||
Fixed: 1
|
Fixed: 1
|
||||||
run:
|
run:
|
||||||
plugin: tab-bar
|
plugin:
|
||||||
|
path: tab-bar
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
body: true
|
body: true
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
|
|
@ -15,7 +16,8 @@ template:
|
||||||
split_size:
|
split_size:
|
||||||
Fixed: 2
|
Fixed: 2
|
||||||
run:
|
run:
|
||||||
plugin: status-bar
|
plugin:
|
||||||
|
path: status-bar
|
||||||
tabs:
|
tabs:
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
parts:
|
parts:
|
||||||
|
|
@ -23,5 +25,6 @@ tabs:
|
||||||
split_size:
|
split_size:
|
||||||
Percent: 20
|
Percent: 20
|
||||||
run:
|
run:
|
||||||
plugin: strider
|
plugin:
|
||||||
|
path: strider
|
||||||
- direction: Horizontal
|
- direction: Horizontal
|
||||||
|
|
|
||||||
|
|
@ -53,11 +53,19 @@ pub enum SplitSize {
|
||||||
#[serde(crate = "self::serde")]
|
#[serde(crate = "self::serde")]
|
||||||
pub enum Run {
|
pub enum Run {
|
||||||
#[serde(rename = "plugin")]
|
#[serde(rename = "plugin")]
|
||||||
Plugin(Option<PathBuf>),
|
Plugin(Option<RunPlugin>),
|
||||||
#[serde(rename = "command")]
|
#[serde(rename = "command")]
|
||||||
Command(RunCommand),
|
Command(RunCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(crate = "self::serde")]
|
||||||
|
pub struct RunPlugin {
|
||||||
|
pub path: PathBuf,
|
||||||
|
#[serde(default)]
|
||||||
|
pub _allow_exec_host_cmd: bool,
|
||||||
|
}
|
||||||
|
|
||||||
// The layout struct ultimately used to build the layouts.
|
// The layout struct ultimately used to build the layouts.
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
#[serde(crate = "self::serde")]
|
#[serde(crate = "self::serde")]
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,16 @@ template:
|
||||||
split_size:
|
split_size:
|
||||||
Fixed: 1
|
Fixed: 1
|
||||||
run:
|
run:
|
||||||
plugin: tab-bar
|
plugin:
|
||||||
|
path: tab-bar
|
||||||
- direction: Horizontal
|
- direction: Horizontal
|
||||||
body: true
|
body: true
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
split_size:
|
split_size:
|
||||||
Fixed: 2
|
Fixed: 2
|
||||||
run:
|
run:
|
||||||
plugin: status-bar
|
plugin:
|
||||||
|
path: status-bar
|
||||||
|
|
||||||
tabs:
|
tabs:
|
||||||
- direction: Vertical
|
- direction: Vertical
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,10 @@ fn default_layout_merged_correctly() {
|
||||||
borderless: true,
|
borderless: true,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(1)),
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "tab-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
Layout {
|
Layout {
|
||||||
direction: Direction::Vertical,
|
direction: Direction::Vertical,
|
||||||
|
|
@ -59,7 +62,10 @@ fn default_layout_merged_correctly() {
|
||||||
borderless: true,
|
borderless: true,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(2)),
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
run: Some(Run::Plugin(Some("status-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "status-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
split_size: None,
|
split_size: None,
|
||||||
|
|
@ -83,7 +89,10 @@ fn default_layout_new_tab_correct() {
|
||||||
borderless: true,
|
borderless: true,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(1)),
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "tab-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
Layout {
|
Layout {
|
||||||
direction: Direction::Horizontal,
|
direction: Direction::Horizontal,
|
||||||
|
|
@ -97,7 +106,10 @@ fn default_layout_new_tab_correct() {
|
||||||
borderless: true,
|
borderless: true,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(2)),
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
run: Some(Run::Plugin(Some("status-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "status-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
split_size: None,
|
split_size: None,
|
||||||
|
|
@ -253,7 +265,10 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
|
||||||
borderless: false,
|
borderless: false,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(1)),
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "tab-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
Layout {
|
Layout {
|
||||||
direction: Direction::Vertical,
|
direction: Direction::Vertical,
|
||||||
|
|
@ -297,7 +312,10 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
|
||||||
borderless: false,
|
borderless: false,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(2)),
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
run: Some(Run::Plugin(Some("status-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "status-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
split_size: None,
|
split_size: None,
|
||||||
|
|
@ -321,7 +339,10 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
|
||||||
borderless: false,
|
borderless: false,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(1)),
|
split_size: Some(SplitSize::Fixed(1)),
|
||||||
run: Some(Run::Plugin(Some("tab-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "tab-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
Layout {
|
Layout {
|
||||||
direction: Direction::Horizontal,
|
direction: Direction::Horizontal,
|
||||||
|
|
@ -335,7 +356,10 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
|
||||||
borderless: false,
|
borderless: false,
|
||||||
parts: vec![],
|
parts: vec![],
|
||||||
split_size: Some(SplitSize::Fixed(2)),
|
split_size: Some(SplitSize::Fixed(2)),
|
||||||
run: Some(Run::Plugin(Some("status-bar".into()))),
|
run: Some(Run::Plugin(Some(RunPlugin {
|
||||||
|
path: "status-bar".into(),
|
||||||
|
..Default::default()
|
||||||
|
}))),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
split_size: None,
|
split_size: None,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue