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}