1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#![cfg_attr(not(feature = "std"), no_std)]

use core::ffi::c_int as RawFd;
extern crate alloc;

pub mod op;
mod listenfd;

pub use listenfd::ListenFd;

/// A raw file descriptor, opened for us by the environment.
///
/// The code does assume to own it, but it won't close the file descriptor.
pub struct SharedFd {
    fd: RawFd,
}

impl SharedFd {
    /// Import a shared file descriptor based on environment variable `SHM_SHARED_FDS`.
    ///
    /// # Safety
    /// Caller asserts that the environment variable has been set to a file descriptor that is not
    /// owned by any other resource.
    #[cfg(all(feature = "std", feature = "libc"))]
    pub unsafe fn from_env() -> Option<Self> {
        let listen = ListenFd::new()?.ok()?;
        Self::from_listen(&listen)
    }

    /// Import a shared file descriptor based on the contents that would be in the environment variable `SHM_SHARED_FDS`.
    #[cfg(all(feature = "libc"))]
    unsafe fn from_listen(var: &ListenFd) -> Option<Self> {
        let num = var.names.iter().position(|v|v == "SHM_SHARED_FD")?;
        let fd: RawFd = var.fd_base + num as RawFd;

        let mut statbuf = unsafe { core::mem::zeroed::<libc::stat>() };
        if -1 == unsafe { libc::fstat(fd, &mut statbuf) } {
            // FIXME: Report that error?
            return None;
        }

        Some(SharedFd { fd })
    }

    /// Open the file descriptor.
    ///
    /// This can fail if for some reason the file descriptor does not refer to an anonymous memory
    /// file.
    #[cfg(all(feature = "memfile", feature = "std"))]
    pub fn into_file(self) -> Result<memfile::MemFile, std::io::Error> {
        let fd = self.into_raw_fd();
        // It's not necessary to preserve the file descriptor here.
        // It can be restored in any case.
        memfile::MemFile::from_file(fd).map_err(|err| err.into_error())
    }

    pub fn as_raw_fd(&self) -> RawFd {
        self.fd
    }

    pub fn into_raw_fd(self) -> RawFd {
        let _this = core::mem::ManuallyDrop::new(self);
        _this.fd
    }
}

#[cfg(feature = "std")]
impl std::os::unix::io::AsRawFd for SharedFd {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}