use crate::jailer::common;
use crate::runtime::advanced_options::ResourceLimits;
use crate::util::{PidFileWriter, PidRecord};
use std::os::fd::RawFd;
use std::process::Command;
pub fn add_pre_exec_hook(
cmd: &mut Command,
resource_limits: ResourceLimits,
pid_writer: Option<PidFileWriter>,
preserved_fds: Vec<(RawFd, i32)>,
detach: bool,
) {
use std::os::unix::process::CommandExt;
if !detach {
cmd.process_group(0);
}
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 writer) = pid_writer {
writer
.write(&PidRecord::current())
.map_err(std::io::Error::from_raw_os_error)?;
}
if detach && libc::setsid() == -1 {
return Err(std::io::Error::last_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![], false);
}
#[test]
fn test_add_hook_with_pid_file() {
let mut cmd = Command::new("/bin/echo");
let limits = ResourceLimits::default();
let writer = PidFileWriter::at(std::path::Path::new("/tmp/test.pid")).ok();
add_pre_exec_hook(&mut cmd, limits, writer, vec![], false);
}
#[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)], false);
}
}