#![allow(unused_unsafe)]
use std::os::{unix::io::RawFd, fd::{OwnedFd, AsRawFd, FromRawFd}};
#[derive(Debug)]
pub enum Fd {
None,
Owned(OwnedFd),
Borrowed(RawFd),
}
fn _errno() -> i32 {
std::io::Error::last_os_error().raw_os_error().unwrap_or(0)
}
fn retry<F: Fn() -> i32>(f: F) -> std::io::Result<i32> {
loop {
let rc = f();
if rc >= 0 {
break Ok(rc);
} else {
let e = std::io::Error::last_os_error();
if e.kind() != std::io::ErrorKind::Interrupted {
break Err(e)
}
}
}
}
impl From<OwnedFd> for Fd {
fn from(value: OwnedFd) -> Self {
Self::Owned(value)
}
}
impl Fd {
pub unsafe fn from_raw_fd(fd: RawFd) -> Self {
OwnedFd::from_raw_fd(fd).into()
}
pub unsafe fn share_raw_fd(fd: RawFd) -> Self {
Self::Borrowed(fd)
}
fn try_as_raw_fd(&self) -> Option<RawFd> {
match self {
Self::None => None,
Self::Owned(fd) => Some(fd.as_raw_fd()),
Self::Borrowed(fd) => Some(fd.as_raw_fd()),
}
}
pub fn close(&mut self) {
*self = Self::None;
}
pub unsafe fn ioctl_ptr<T>(&self, request: libc::c_ulong, p: *mut T) -> std::io::Result<i32> {
match self.try_as_raw_fd() {
Some(fd) => retry(|| unsafe { libc::ioctl(fd, request, p) }),
None => Err(std::io::Error::from_raw_os_error(libc::EBADF)),
}
}
pub unsafe fn ioctl_ptrc<T>(&self, request: libc::c_ulong, p: *const T) -> std::io::Result<i32>
{
let p_mut: *mut T = std::mem::transmute(p);
self.ioctl_ptr(request, p_mut)
}
pub unsafe fn mmap(&self, addr: *mut libc::c_void, len: libc::size_t, prot: libc::c_int,
flags: libc::c_int, offset: libc::off_t) -> std::io::Result<*mut libc::c_void>
{
match self.try_as_raw_fd() {
Some(fd) => {
match unsafe { libc::mmap(addr, len, prot, flags, fd, offset) } {
rc if rc == libc::MAP_FAILED => Err(std::io::Error::last_os_error()),
addr => Ok(addr),
}
}
None => Err(std::io::Error::from_raw_os_error(libc::EBADF)),
}
}
}