use std::os::fd::RawFd;
use crate::{ShellFd, error, openfiles};
const FIRST_DUPLICATE_FD: RawFd = 3;
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
const FD_DIR_PATH: &str = "/proc/self/fd";
} else if #[cfg(any(
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))] {
const FD_DIR_PATH: &str = "/dev/fd";
} else {
pub fn iter_fds()
-> Result<impl Iterator<Item = (ShellFd, openfiles::OpenFile)>, error::Error> {
Ok(std::iter::empty())
}
}
}
#[cfg(any(
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))]
pub fn try_iter_open_fds() -> impl Iterator<Item = (ShellFd, openfiles::OpenFile)> {
std::fs::read_dir(FD_DIR_PATH)
.into_iter()
.flatten()
.filter_map(Result::ok)
.filter_map(|entry| {
let fd: RawFd = entry.file_name().to_str()?.parse().ok()?;
let file = open_file_by_fd(fd).ok()?;
Some((fd, file))
})
}
pub fn try_get_file_for_open_fd(fd: RawFd) -> Option<openfiles::OpenFile> {
open_file_by_fd(fd).ok()
}
fn open_file_by_fd(fd: RawFd) -> Result<openfiles::OpenFile, error::Error> {
use std::os::fd::FromRawFd as _;
let duplicate = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, FIRST_DUPLICATE_FD) };
if duplicate == -1 {
return Err(std::io::Error::last_os_error().into());
}
let owned_fd = unsafe { std::os::fd::OwnedFd::from_raw_fd(duplicate) };
Ok(std::fs::File::from(owned_fd).into())
}