Merge "Revert "Add libinherited_fd crate"" into main
diff --git a/libs/libinherited_fd/Android.bp b/libs/libinherited_fd/Android.bp
deleted file mode 100644
index 28ec2e5..0000000
--- a/libs/libinherited_fd/Android.bp
+++ /dev/null
@@ -1,44 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-rust_defaults {
- name: "libinherited_fd.defaults",
- crate_name: "inherited_fd",
- srcs: ["src/lib.rs"],
- edition: "2021",
- rustlibs: [
- "libnix",
- "libonce_cell",
- "libthiserror",
- ],
-}
-
-rust_library {
- name: "libinherited_fd",
- defaults: ["libinherited_fd.defaults"],
- apex_available: [
- "com.android.compos",
- "com.android.virt",
- ],
-}
-
-rust_test {
- name: "libinherited_fd.test",
- defaults: ["libinherited_fd.defaults"],
- rustlibs: [
- "libanyhow",
- "libtempfile",
- ],
- host_supported: true,
- test_suites: ["general-tests"],
- test_options: {
- unit_test: true,
- },
- // this is to run each test function in a separate process.
- // note that they still run in parallel.
- flags: [
- "-C panic=abort",
- "-Z panic_abort_tests",
- ],
-}
diff --git a/libs/libinherited_fd/src/lib.rs b/libs/libinherited_fd/src/lib.rs
deleted file mode 100644
index f5e2d6b..0000000
--- a/libs/libinherited_fd/src/lib.rs
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright 2024, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Library for safely obtaining `OwnedFd` for inherited file descriptors.
-
-use nix::fcntl::{fcntl, FdFlag, F_SETFD};
-use nix::libc;
-use std::collections::HashMap;
-use std::fs::canonicalize;
-use std::fs::read_dir;
-use std::os::fd::FromRawFd;
-use std::os::fd::OwnedFd;
-use std::os::fd::RawFd;
-use std::sync::Mutex;
-use std::sync::OnceLock;
-use thiserror::Error;
-
-/// Errors that can occur while taking an ownership of `RawFd`
-#[derive(Debug, PartialEq, Error)]
-pub enum Error {
- /// init_once() not called
- #[error("init_once() not called")]
- NotInitialized,
-
- /// Ownership already taken
- #[error("Ownership of FD {0} is already taken")]
- OwnershipTaken(RawFd),
-
- /// Not an inherited file descriptor
- #[error("FD {0} is either invalid file descriptor or not an inherited one")]
- FileDescriptorNotInherited(RawFd),
-
- /// Failed to set CLOEXEC
- #[error("Failed to set CLOEXEC on FD {0}")]
- FailCloseOnExec(RawFd),
-}
-
-static INHERITED_FDS: OnceLock<Mutex<HashMap<RawFd, Option<OwnedFd>>>> = OnceLock::new();
-
-/// Take ownership of all open file descriptors in this process, which later can be obtained by
-/// calling `take_fd_ownership`.
-///
-/// # Safety
-/// This function has to be called very early in the program before the ownership of any file
-/// descriptors (except stdin/out/err) is taken.
-pub unsafe fn init_once() -> Result<(), std::io::Error> {
- let mut fds = HashMap::new();
-
- let fd_path = canonicalize("/proc/self/fd")?;
-
- for entry in read_dir(&fd_path)? {
- let entry = entry?;
-
- // Files in /prod/self/fd are guaranteed to be numbers. So parsing is always successful.
- let file_name = entry.file_name();
- let raw_fd = file_name.to_str().unwrap().parse::<RawFd>().unwrap();
-
- // We don't take ownership of the stdio FDs as the Rust runtime owns them.
- if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
- continue;
- }
-
- // Exceptional case: /proc/self/fd/* may be a dir fd created by read_dir just above. Since
- // the file descriptor is owned by read_dir (and thus closed by it), we shouldn't take
- // ownership to it.
- if entry.path().read_link()? == fd_path {
- continue;
- }
-
- // SAFETY: /proc/self/fd/* are file descriptors that are open. If `init_once()` was called
- // at the very beginning of the program execution (as requested by the safety requirement
- // of this function), this is the first time to claim the ownership of these file
- // descriptors.
- let owned_fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
- fds.insert(raw_fd, Some(owned_fd));
- }
-
- INHERITED_FDS
- .set(Mutex::new(fds))
- .or(Err(std::io::Error::other("Inherited fds were already initialized")))
-}
-
-/// Take the ownership of the given `RawFd` and returns `OwnedFd` for it. The returned FD is set
-/// CLOEXEC. `Error` is returned when the ownership was already taken (by a prior call to this
-/// function with the same `RawFd`) or `RawFd` is not an inherited file descriptor.
-pub fn take_fd_ownership(raw_fd: RawFd) -> Result<OwnedFd, Error> {
- let mut fds = INHERITED_FDS.get().ok_or(Error::NotInitialized)?.lock().unwrap();
-
- if let Some(value) = fds.get_mut(&raw_fd) {
- if let Some(owned_fd) = value.take() {
- fcntl(raw_fd, F_SETFD(FdFlag::FD_CLOEXEC)).or(Err(Error::FailCloseOnExec(raw_fd)))?;
- Ok(owned_fd)
- } else {
- Err(Error::OwnershipTaken(raw_fd))
- }
- } else {
- Err(Error::FileDescriptorNotInherited(raw_fd))
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use anyhow::Result;
- use nix::fcntl::{fcntl, FdFlag, F_GETFD, F_SETFD};
- use nix::unistd::close;
- use std::os::fd::{AsRawFd, IntoRawFd};
- use tempfile::tempfile;
-
- struct Fixture {
- fds: Vec<RawFd>,
- }
-
- impl Fixture {
- fn setup(num_fds: usize) -> Result<Self> {
- let mut fds = Vec::new();
- for _ in 0..num_fds {
- fds.push(tempfile()?.into_raw_fd());
- }
- Ok(Fixture { fds })
- }
-
- fn open_new_file(&mut self) -> Result<RawFd> {
- let raw_fd = tempfile()?.into_raw_fd();
- self.fds.push(raw_fd);
- Ok(raw_fd)
- }
- }
-
- impl Drop for Fixture {
- fn drop(&mut self) {
- self.fds.iter().for_each(|fd| {
- let _ = close(*fd);
- });
- }
- }
-
- fn is_fd_opened(raw_fd: RawFd) -> bool {
- fcntl(raw_fd, F_GETFD).is_ok()
- }
-
- #[test]
- fn happy_case() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f0 = fixture.fds[0];
- let f1 = fixture.fds[1];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f0_owned = take_fd_ownership(f0)?;
- let f1_owned = take_fd_ownership(f1)?;
- assert_eq!(f0, f0_owned.as_raw_fd());
- assert_eq!(f1, f1_owned.as_raw_fd());
-
- drop(f0_owned);
- drop(f1_owned);
- assert!(!is_fd_opened(f0));
- assert!(!is_fd_opened(f1));
- Ok(())
- }
-
- #[test]
- fn access_non_inherited_fd() -> Result<()> {
- let mut fixture = Fixture::setup(2)?;
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f = fixture.open_new_file()?;
- assert_eq!(Some(Error::FileDescriptorNotInherited(f)), take_fd_ownership(f).err());
- Ok(())
- }
-
- #[test]
- fn call_init_once_multiple_times() -> Result<()> {
- let _ = Fixture::setup(2)?;
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- // SAFETY: for testing
- let res = unsafe { init_once() };
- assert!(res.is_err());
- Ok(())
- }
-
- #[test]
- fn access_without_init_once() -> Result<()> {
- let fixture = Fixture::setup(2)?;
-
- let f = fixture.fds[0];
- assert_eq!(Some(Error::NotInitialized), take_fd_ownership(f).err());
- Ok(())
- }
-
- #[test]
- fn double_ownership() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f = fixture.fds[0];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f_owned = take_fd_ownership(f)?;
- let f_double_owned = take_fd_ownership(f);
- assert_eq!(Some(Error::OwnershipTaken(f)), f_double_owned.err());
-
- // just to highlight that f_owned is kept alive when the second call to take_fd_ownership
- // is made.
- drop(f_owned);
- Ok(())
- }
-
- #[test]
- fn take_drop_retake() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f = fixture.fds[0];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f_owned = take_fd_ownership(f)?;
- drop(f_owned);
-
- let f_double_owned = take_fd_ownership(f);
- assert_eq!(Some(Error::OwnershipTaken(f)), f_double_owned.err());
- Ok(())
- }
-
- #[test]
- fn cloexec() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f = fixture.fds[0];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- // Intentionally cleaar cloexec to see if it is set by take_fd_ownership
- fcntl(f, F_SETFD(FdFlag::empty()))?;
-
- let f_owned = take_fd_ownership(f)?;
- let flags = fcntl(f_owned.as_raw_fd(), F_GETFD)?;
- assert_eq!(flags, FdFlag::FD_CLOEXEC.bits());
- Ok(())
- }
-}