diff --git a/storefd-listen/src/lib.rs b/storefd-listen/src/lib.rs index 249d82b..bdb5fcf 100644 --- a/storefd-listen/src/lib.rs +++ b/storefd-listen/src/lib.rs @@ -1,22 +1,27 @@ //! Support for file descriptor passing with `LISTEN_FD` //! -//! The entrypoints of this module are [`FileDescriptor::receive()`] and [`FileDescriptor::receive_with_names()`]. (And their **`unsafe`** `*_no_dup` variants.) +//! The entrypoints of this module are [`FileDescriptor::receive()`] and [`FileDescriptor::receive_with_names()`]. (And their `*_no_dup` variants.) +//! +//! **All the `receive` functions are unsafe as they rely on states that cannot be checked by the +//! rust compiler** (namely that the raw filedescriptors passed to the program (that aren't known +//! to the compiler) haven't been taken or closed already). //! //! ```no_run -//! # main() -> Result<(), Box> { -//! let received_fd: Vec = FileDescriptor::receive_with_names(true) -//! .into_iter() -//! .filter_map(|(name, res)| { -//! if name == "" { -//! Some(res) -//! } else { -//! None -//! } -//! }) -//! .collect()? -//! // Use the received file descriptors. -//! # Ok(()) -//! # } +//! main() -> Result<(), Box> { +//! // SAFETY: First thing we are doing so the file descriptors shouldn't have changed since they were passed to us. +//! let received_fd: Vec = unsafe { FileDescriptor::receive_with_names(true) } +//! .into_iter() +//! .filter_map(|(name, res)| { +//! if name == "" { +//! Some(res) +//! } else { +//! None +//! } +//! }) +//! .collect()? +//! // Use the received file descriptors. +//! Ok(()) +//! } //! ``` use std::ffi::{OsStr, OsString}; use std::fs::File; @@ -105,7 +110,13 @@ impl FileDescriptor { /// # Errors /// /// This function will fail if no file descriptor could be received which might not actually be an error. See [`ReceiveError`] for details. - pub fn receive( + /// + /// # Safety + /// + /// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed. + /// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)). + /// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors. + pub unsafe fn receive( unset_env: bool, ) -> Result>, ReceiveError> { log::trace!("Receiving file descriptors."); @@ -129,7 +140,7 @@ impl FileDescriptor { /// /// # Safety /// - /// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct. + /// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed. /// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)). /// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors. pub unsafe fn receive_no_dup() -> Result, ReceiveError> { @@ -139,7 +150,7 @@ impl FileDescriptor { Self::from_fds_no_dup(fds).map_err(ReceiveError::GetFds) } - fn inner_receive(unset_env: bool) -> Result { + unsafe fn inner_receive(unset_env: bool) -> Result { let pid = env::var_os(PID_VAR).ok_or(ReceiveError::NoListenPID)?; let fds = env::var_os(FD_NUMBER_VAR).ok_or(ReceiveError::NoListenFD)?; log::trace!("{PID_VAR} = {pid:?}; {FD_NUMBER_VAR} = {fds:?}"); @@ -181,7 +192,13 @@ impl FileDescriptor { /// # Errors /// /// This function will fail if no file descriptors could be obtained or the names associated with them couldn't be obtained. See [`ReceiveNameError`] for details. - pub fn receive_with_names( + /// + /// # Safety + /// + /// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed. + /// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)). + /// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors. + pub unsafe fn receive_with_names( unset_env: bool, ) -> Result)>, ReceiveNameError> { @@ -203,7 +220,7 @@ impl FileDescriptor { /// /// # Safety /// - /// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct. + /// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed. /// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)). /// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors. pub unsafe fn receive_with_names_no_dup( @@ -228,7 +245,7 @@ impl FileDescriptor { .collect::>()) } - fn from_fd_offset(fd_offset: usize) -> Result { + unsafe fn from_fd_offset(fd_offset: usize) -> Result { SD_LISTEN_FDS_START .checked_add(fd_offset as RawFd) .map(|fd| { @@ -240,14 +257,14 @@ impl FileDescriptor { .map(Self::from_fd) } - fn from_fds( + unsafe fn from_fds( num_fds: usize, ) -> Result>, GetFdsError> { if SD_LISTEN_FDS_START.checked_add(num_fds as RawFd).is_none() { return Err(GetFdsError::TooManyFDs(num_fds)); } - let ret = (0..num_fds).map(Self::from_fd_offset); + let ret = (0..num_fds).map(|fd_offset| unsafe { Self::from_fd_offset(fd_offset) }); Ok(ret) }