shm_fd/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3/// Interact with the systemd File Descriptor store (or equivalent).
4///
5/// This crate implements pure Rust wrappers to access a set of environment variables describing
6/// file descriptors pre-opened by the parent process. This is used to pass the kernel state
7/// maintained by a service manager to the service. Commonly, this may be a network socket to avoid
8/// connection loss on restarts, or a shared memory area to retain in-memory state across restarts.
9///
10/// The crate only captures mainly the primary file-descriptor mechanism. Higher level semantics
11/// such as interpreting the contents of a memory file or socket are left to other library
12/// components.
13///
14/// ## Binary Target
15///
16/// The crate also defines a binary target. This program serves as example and can be utilized as a
17/// wrapper binary to bring up the File Descriptor store on a cold restart. It makes sure a shm
18/// file exists as a named file descriptor in the store.
19use core::ffi::c_int as RawFd;
20
21extern crate alloc;
22
23mod listenfd;
24// FIXME: tried, but not as useful as intended. There are a few types we use in interfaces and
25// representations which would have to be modelled, too (for the std::env::var_os and for
26// libc::AF_UNIX / libc::sendmsg mostly).
27//
28// Hence, this module is private for now until that representation is figured out.
29mod op;
30#[cfg(all(feature = "std", feature = "libc"))]
31mod notifyfd;
32
33pub use listenfd::{ListenFd, ListenInit};
34#[cfg(all(feature = "std", feature = "libc"))]
35pub use notifyfd::NotifyFd;
36
37/// A raw file descriptor, opened for us by the environment.
38///
39/// The code does assume to own it, but it won't close the file descriptor.
40pub struct SharedFd {
41    fd: RawFd,
42}
43
44impl SharedFd {
45    /// Import a shared file descriptor based on environment variable `SHM_SHARED_FDS`.
46    ///
47    /// # Safety
48    /// Caller asserts that the environment variable has been set to a file descriptor that is not
49    /// owned by any other resource.
50    #[cfg(all(feature = "std", feature = "libc"))]
51    pub unsafe fn from_env() -> Option<Self> {
52        let listen = ListenFd::new()?.ok()?;
53        Self::from_listen(&listen)
54    }
55
56    /// Import a shared file descriptor based on the contents that would be in the environment variable `SHM_SHARED_FDS`.
57    #[cfg(all(feature = "libc"))]
58    pub unsafe fn from_listen(var: &ListenFd) -> Option<Self> {
59        let num = var.names.iter().position(|v|v == "SHM_SHARED_FD")?;
60        let fd: RawFd = var.fd_base + num as RawFd;
61
62        if -1 == (op::ShmVTable::new_libc().fstat)(fd, None) {
63            // FIXME: Report that error?
64            return None;
65        }
66
67        Some(SharedFd { fd })
68    }
69
70    /// Open the file descriptor.
71    ///
72    /// This can fail if for some reason the file descriptor does not refer to an anonymous memory
73    /// file.
74    #[cfg(all(feature = "memfile", feature = "std"))]
75    pub fn into_file(self) -> Result<memfile::MemFile, std::io::Error> {
76        let fd = self.into_raw_fd();
77        // It's not necessary to preserve the file descriptor here.
78        // It can be restored in any case.
79        memfile::MemFile::from_file(fd).map_err(|err| err.into_error())
80    }
81
82    pub fn as_raw_fd(&self) -> RawFd {
83        self.fd
84    }
85
86    /// Grab the raw fie descriptor.
87    pub fn into_raw_fd(self) -> RawFd {
88        let _this = core::mem::ManuallyDrop::new(self);
89        _this.fd
90    }
91}
92
93#[cfg(feature = "std")]
94impl std::os::unix::io::AsRawFd for SharedFd {
95    fn as_raw_fd(&self) -> RawFd {
96        self.fd
97    }
98}