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 {
|
||||
let (pid_tx, pid_rx) = channel();
|
||||
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();
|
||||
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(
|
||||
pid,
|
||||
*position_and_size,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use log::info;
|
||||
use log::{info, warn};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -28,7 +28,7 @@ use zellij_utils::{input::command::TerminalAction, serde, zellij_tile};
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
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
|
||||
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
||||
Unload(u32),
|
||||
|
|
@ -54,6 +54,8 @@ pub(crate) struct PluginEnv {
|
|||
pub senders: ThreadSenders,
|
||||
pub wasi_env: WasiEnv,
|
||||
pub subscriptions: Arc<Mutex<HashSet<EventType>>>,
|
||||
// FIXME: Once permission system is ready, this could be removed
|
||||
pub _allow_exec_host_cmd: bool,
|
||||
}
|
||||
|
||||
// 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");
|
||||
err_ctx.add_call(ContextType::Plugin((&event).into()));
|
||||
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 wasm_bytes = fs::read(&path)
|
||||
.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();
|
||||
|
||||
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 {
|
||||
plugin_id,
|
||||
tab_index,
|
||||
senders: bus.senders.clone(),
|
||||
wasi_env,
|
||||
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
||||
_allow_exec_host_cmd,
|
||||
};
|
||||
|
||||
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_open_file,
|
||||
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 ---------------------------------------------------------------------------------------------------
|
||||
|
||||
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) {
|
||||
unsafe { host_set_timeout(secs) };
|
||||
}
|
||||
pub fn exec_cmd(cmd: &[&str]) {
|
||||
object_to_stdout(&cmd);
|
||||
unsafe { host_exec_cmd() };
|
||||
}
|
||||
|
||||
// Internal Functions
|
||||
|
||||
|
|
@ -60,4 +64,5 @@ extern "C" {
|
|||
fn host_get_plugin_ids();
|
||||
fn host_open_file();
|
||||
fn host_set_timeout(secs: f64);
|
||||
fn host_exec_cmd();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ template:
|
|||
split_size:
|
||||
Fixed: 1
|
||||
run:
|
||||
plugin: tab-bar
|
||||
plugin:
|
||||
path: tab-bar
|
||||
- direction: Vertical
|
||||
body: true
|
||||
- direction: Vertical
|
||||
|
|
@ -15,6 +16,7 @@ template:
|
|||
split_size:
|
||||
Fixed: 2
|
||||
run:
|
||||
plugin: status-bar
|
||||
plugin:
|
||||
path: status-bar
|
||||
tabs:
|
||||
- direction: Vertical
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ template:
|
|||
split_size:
|
||||
Fixed: 1
|
||||
run:
|
||||
plugin: tab-bar
|
||||
plugin:
|
||||
path: tab-bar
|
||||
- direction: Vertical
|
||||
body: true
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ template:
|
|||
split_size:
|
||||
Fixed: 1
|
||||
run:
|
||||
plugin: tab-bar
|
||||
plugin:
|
||||
path: tab-bar
|
||||
- direction: Vertical
|
||||
body: true
|
||||
- direction: Vertical
|
||||
|
|
@ -15,7 +16,8 @@ template:
|
|||
split_size:
|
||||
Fixed: 2
|
||||
run:
|
||||
plugin: status-bar
|
||||
plugin:
|
||||
path: status-bar
|
||||
tabs:
|
||||
- direction: Vertical
|
||||
parts:
|
||||
|
|
@ -23,5 +25,6 @@ tabs:
|
|||
split_size:
|
||||
Percent: 20
|
||||
run:
|
||||
plugin: strider
|
||||
plugin:
|
||||
path: strider
|
||||
- direction: Horizontal
|
||||
|
|
|
|||
|
|
@ -53,11 +53,19 @@ pub enum SplitSize {
|
|||
#[serde(crate = "self::serde")]
|
||||
pub enum Run {
|
||||
#[serde(rename = "plugin")]
|
||||
Plugin(Option<PathBuf>),
|
||||
Plugin(Option<RunPlugin>),
|
||||
#[serde(rename = "command")]
|
||||
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.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[serde(crate = "self::serde")]
|
||||
|
|
|
|||
|
|
@ -6,14 +6,16 @@ template:
|
|||
split_size:
|
||||
Fixed: 1
|
||||
run:
|
||||
plugin: tab-bar
|
||||
plugin:
|
||||
path: tab-bar
|
||||
- direction: Horizontal
|
||||
body: true
|
||||
- direction: Vertical
|
||||
split_size:
|
||||
Fixed: 2
|
||||
run:
|
||||
plugin: status-bar
|
||||
plugin:
|
||||
path: status-bar
|
||||
|
||||
tabs:
|
||||
- direction: Vertical
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ fn default_layout_merged_correctly() {
|
|||
borderless: true,
|
||||
parts: vec![],
|
||||
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 {
|
||||
direction: Direction::Vertical,
|
||||
|
|
@ -59,7 +62,10 @@ fn default_layout_merged_correctly() {
|
|||
borderless: true,
|
||||
parts: vec![],
|
||||
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,
|
||||
|
|
@ -83,7 +89,10 @@ fn default_layout_new_tab_correct() {
|
|||
borderless: true,
|
||||
parts: vec![],
|
||||
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 {
|
||||
direction: Direction::Horizontal,
|
||||
|
|
@ -97,7 +106,10 @@ fn default_layout_new_tab_correct() {
|
|||
borderless: true,
|
||||
parts: vec![],
|
||||
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,
|
||||
|
|
@ -253,7 +265,10 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
|
|||
borderless: false,
|
||||
parts: vec![],
|
||||
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 {
|
||||
direction: Direction::Vertical,
|
||||
|
|
@ -297,7 +312,10 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
|
|||
borderless: false,
|
||||
parts: vec![],
|
||||
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,
|
||||
|
|
@ -321,7 +339,10 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
|
|||
borderless: false,
|
||||
parts: vec![],
|
||||
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 {
|
||||
direction: Direction::Horizontal,
|
||||
|
|
@ -335,7 +356,10 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
|
|||
borderless: false,
|
||||
parts: vec![],
|
||||
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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue