use std::convert::Infallible;
use std::ffi::CStr;
use std::fs::File;
use std::os::fd::{FromRawFd, IntoRawFd};
use libc::fexecve;
use rustix::fd::IntoRawFd as _;
use rustix::fd::OwnedFd;
use rustix::fs::{MemfdFlags, memfd_create};
use super::{Build, Executable};
impl Executable for Build<'_> {
unsafe fn exec(
self,
argc: i32,
argv: *const *const i8,
envp: *const *const i8,
) -> Result<Infallible, proc_exit::Exit> {
let memfd_name = if argc > 0 {
unsafe { CStr::from_ptr(*argv) }
} else {
c""
};
let mut file = memfd_create(memfd_name, MemfdFlags::CLOEXEC)
.map(OwnedFd::into_raw_fd)
.map(|fd| unsafe { File::from_raw_fd(fd) })
.map_err(|_| {
proc_exit::Code::FAILURE.with_message("Failed to create an anonymous memory file")
})?;
self.extract_into(&mut file).map_err(|_| {
proc_exit::Code::FAILURE
.with_message("Failed to write the build to an anonymous memory file")
})?;
let fd = file.into_raw_fd();
unsafe { fexecve(fd, argv, envp) };
let mut error = std::io::Error::last_os_error();
if error.raw_os_error() == Some(libc::ENOENT) {
let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
if flags >= 0
&& unsafe { libc::fcntl(fd, libc::F_SETFD, flags & !libc::FD_CLOEXEC) } >= 0
{
unsafe { fexecve(fd, argv, envp) };
error = std::io::Error::last_os_error();
}
}
Err(proc_exit::Code::FAILURE.with_message(format!("Failed to execute the build: {error}")))
}
}