Skip to main content

start_command/
isolation_shell.rs

1//! Shell command classification shared by isolation backends.
2
3const SHELL_NAMES: [&str; 8] = ["bash", "zsh", "sh", "fish", "ksh", "csh", "tcsh", "dash"];
4
5pub fn is_interactive_shell_command(command: &str) -> bool {
6    let parts: Vec<&str> = command.split_whitespace().collect();
7    if parts.is_empty() {
8        return false;
9    }
10    let basename = parts[0].rsplit('/').next().unwrap_or(parts[0]);
11    SHELL_NAMES.contains(&basename) && !parts.contains(&"-c")
12}
13
14pub fn is_shell_invocation_with_args(command: &str) -> bool {
15    let parts: Vec<&str> = command.split_whitespace().collect();
16    if parts.is_empty() {
17        return false;
18    }
19    let basename = parts[0].rsplit('/').next().unwrap_or(parts[0]);
20    SHELL_NAMES.contains(&basename) && parts.contains(&"-c")
21}
22
23pub fn build_shell_with_args_cmd_args(command: &str) -> Vec<String> {
24    let parts: Vec<&str> = command.split_whitespace().collect();
25    let Some(index) = parts.iter().position(|&part| part == "-c") else {
26        return parts.iter().map(|part| (*part).to_string()).collect();
27    };
28    let script = parts[index + 1..].join(" ");
29    let mut result = parts[..=index]
30        .iter()
31        .map(|part| (*part).to_string())
32        .collect::<Vec<_>>();
33    if !script.is_empty() {
34        result.push(script);
35    }
36    result
37}