use std::process::Command;
use crate::VmError;
use super::backend::ActiveBackend;
use super::{active_sandbox_policy, build_std_command, build_tokio_command, process_output};
macro_rules! close_env_for_session {
($command:expr, $program:expr) => {
if let Some(env) =
crate::stdlib::process::session_closed_env_for_command($program, std::iter::empty())?
{
$command.env_clear();
for (key, value) in env {
$command.env(key, value);
}
true
} else {
false
}
};
}
pub fn session_std_command(program: impl AsRef<std::ffi::OsStr>) -> Result<Command, VmError> {
let program = program.as_ref();
let mut command = Command::new(program);
close_env_for_session!(command, &program.to_string_lossy());
Ok(command)
}
pub fn session_tokio_command(
program: impl AsRef<std::ffi::OsStr>,
) -> Result<tokio::process::Command, VmError> {
let program = program.as_ref();
let mut command = tokio::process::Command::new(program);
close_env_for_session!(command, &program.to_string_lossy());
Ok(command)
}
pub fn std_command_for(program: &str, args: &[String]) -> Result<Command, VmError> {
std_command_for_with_env_state(program, args).map(|(command, _)| command)
}
pub fn std_command_for_with_env_state(
program: &str,
args: &[String],
) -> Result<(Command, bool), VmError> {
let resolved_program = crate::stdlib::process::resolve_program_path_for_spawn(program);
let active = active_sandbox_policy();
let command = match active.as_ref() {
Some((policy, profile)) => {
build_std_command::<ActiveBackend>(&resolved_program, args, policy, *profile)?
}
None => {
let mut command = Command::new(&resolved_program);
command.args(args);
command
}
};
let (mut command, env_closed) = close_std_command_environment(command, program)?;
if let Some(proxy) = active.and_then(|(policy, _)| policy.process_network_proxy) {
process_output::apply_managed_proxy_env(&mut command, proxy);
}
Ok((command, env_closed))
}
fn close_std_command_environment(
mut command: Command,
program: &str,
) -> Result<(Command, bool), VmError> {
let env_closed = close_env_for_session!(command, program);
Ok((command, env_closed))
}
#[cfg(target_os = "linux")]
pub fn command_for_reexec(
program: &str,
args: &[String],
ruleset_fd: i32,
) -> Result<(Command, bool, Option<super::linux::ReexecConfinement>), VmError> {
use super::linux::{launcher_argv_with_ruleset, resolve_netns_launcher, ReexecConfinement};
let resolved = crate::stdlib::process::resolve_program_path_for_spawn(program);
let mut command = Command::new(&resolved);
command.args(args);
let confinement = match super::linux::transferable_confinement(program)? {
None => None,
Some(confinement) => {
let (policy, _) = active_sandbox_policy().expect("confinement requires policy");
if let Some(launcher) = resolve_netns_launcher(&policy)? {
command = Command::new(launcher);
command.args(launcher_argv_with_ruleset(
&resolved,
args,
&confinement,
confinement.ruleset_fd().map(|_| ruleset_fd),
));
Some(ReexecConfinement::AfterNamespace(confinement))
} else {
Some(ReexecConfinement::BeforeExec(confinement))
}
}
};
let (command, env_closed) = close_std_command_environment(command, program)?;
Ok((command, env_closed, confinement))
}
pub fn tokio_command_for(
program: &str,
args: &[String],
) -> Result<tokio::process::Command, VmError> {
let resolved_program = crate::stdlib::process::resolve_program_path_for_spawn(program);
let active = active_sandbox_policy();
let mut command = match active.as_ref() {
Some((policy, profile)) => {
build_tokio_command::<ActiveBackend>(&resolved_program, args, policy, *profile)?
}
None => {
let mut command = tokio::process::Command::new(&resolved_program);
command.args(args);
command
}
};
close_env_for_session!(command, program);
if let Some(proxy) = active.and_then(|(policy, _)| policy.process_network_proxy) {
process_output::apply_managed_proxy_env_tokio(&mut command, proxy);
}
Ok(command)
}