use crate::jailer::common;
use crate::runtime::advanced_options::ResourceLimits;
use std::os::fd::RawFd;
use std::process::Command;
pub fn add_pre_exec_hook(
cmd: &mut Command,
resource_limits: ResourceLimits,
pid_file_path: Option<std::ffi::CString>,
preserved_fds: Vec<(RawFd, i32)>,
) {
use std::os::unix::process::CommandExt;
unsafe {
cmd.pre_exec(move || {
if !preserved_fds.is_empty() {
for &(source, target) in &preserved_fds {
if source != target {
libc::dup2(source, target);
}
}
let first_close = preserved_fds.iter().map(|(_, t)| *t).max().unwrap() + 1;
common::fd::close_fds_from(first_close)
.map_err(std::io::Error::from_raw_os_error)?;
} else {
common::fd::close_inherited_fds_raw().map_err(std::io::Error::from_raw_os_error)?;
}
common::rlimit::apply_limits_raw(&resource_limits)
.map_err(std::io::Error::from_raw_os_error)?;
if let Some(ref path) = pid_file_path {
common::pid::write_pid_file_raw(path).map_err(std::io::Error::from_raw_os_error)?;
}
Ok(())
});
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_hook_compiles() {
let mut cmd = Command::new("/bin/echo");
let limits = ResourceLimits::default();
add_pre_exec_hook(&mut cmd, limits, None, vec![]);
}
#[test]
fn test_add_hook_with_pid_file() {
use std::ffi::CString;
let mut cmd = Command::new("/bin/echo");
let limits = ResourceLimits::default();
let pid_file = CString::new("/tmp/test.pid").ok();
add_pre_exec_hook(&mut cmd, limits, pid_file, vec![]);
}
#[test]
fn test_add_hook_with_preserved_fds() {
let mut cmd = Command::new("/bin/echo");
let limits = ResourceLimits::default();
add_pre_exec_hook(&mut cmd, limits, None, vec![(5, 3)]);
}
}