use crate::CoreError;
use crate::error::syscall_ret;
pub enum ForkResult {
Parent(i32),
Child,
}
pub unsafe fn fork() -> Result<ForkResult, CoreError> {
let pid = unsafe { libc::fork() };
if pid < 0 {
return Err(CoreError::sys(
std::io::Error::last_os_error().raw_os_error().unwrap_or(-1),
"fork",
));
}
if pid == 0 {
Ok(ForkResult::Child)
} else {
Ok(ForkResult::Parent(pid))
}
}
pub fn setsid() -> Result<(), CoreError> {
let ret = unsafe { libc::setsid() };
if ret < 0 {
return Err(CoreError::sys(
std::io::Error::last_os_error().raw_os_error().unwrap_or(-1),
"setsid",
));
}
Ok(())
}
pub fn setpgid(pid: i32, pgid: i32) -> Result<(), CoreError> {
syscall_ret(unsafe { libc::setpgid(pid, pgid) }, "setpgid")
}
pub unsafe fn redirect_stdio_to_devnull() -> Result<(), CoreError> {
let fd = unsafe { libc::open(c"/dev/null".as_ptr(), libc::O_RDWR) };
if fd < 0 {
return Err(CoreError::sys(
std::io::Error::last_os_error().raw_os_error().unwrap_or(-1),
"open:/dev/null",
));
}
unsafe {
libc::dup2(fd, 0);
libc::dup2(fd, 1);
libc::dup2(fd, 2);
if fd > 2 {
libc::close(fd);
}
}
Ok(())
}
pub fn set_pdeathsig(sig: i32) -> Result<(), CoreError> {
syscall_ret(
unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, sig as libc::c_ulong, 0, 0, 0) },
"prctl:PR_SET_PDEATHSIG",
)
}
pub unsafe fn redirect_fd_to(src_fd: i32, dst_fd: i32) {
unsafe {
libc::dup2(src_fd, dst_fd);
libc::close(src_fd);
}
}
pub fn getuid() -> u32 {
unsafe { libc::getuid() }
}
pub fn getgid() -> u32 {
unsafe { libc::getgid() }
}
pub fn setuid(uid: u32) -> Result<(), CoreError> {
syscall_ret(unsafe { libc::setresuid(uid, uid, uid) }, "setresuid")
}
pub fn setgid(gid: u32) -> Result<(), CoreError> {
syscall_ret(unsafe { libc::setresgid(gid, gid, gid) }, "setresgid")
}
pub fn close_fds_from(start: i32) {
let dir = unsafe { libc::opendir(c"/proc/self/fd".as_ptr()) };
if dir.is_null() {
for fd in start..1024 {
unsafe { libc::close(fd) };
}
return;
}
let dir_fd = unsafe { libc::dirfd(dir) };
let mut fds = Vec::new();
loop {
let ent = unsafe { libc::readdir(dir) };
if ent.is_null() {
break;
}
let name = unsafe { (*ent).d_name.as_ptr() };
let name = unsafe { std::ffi::CStr::from_ptr(name) };
let Ok(name) = name.to_str() else { continue };
if let Ok(fd) = name.parse::<i32>() {
if fd >= start && fd != dir_fd {
fds.push(fd);
}
}
}
unsafe { libc::closedir(dir) };
for fd in fds {
unsafe { libc::close(fd) };
}
}