pidfd_util/lib.rs
1// SPDX-FileCopyrightText: 2026 The pidfd-util-rs authors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Safe Rust wrapper for Linux process file descriptors (pidfd).
5//!
6//! This crate provides a safe, ergonomic interface to Linux's pidfd API, which represents
7//! processes as file descriptors. Unlike traditional PIDs, pidfds cannot be reused after a
8//! process exits, making them safe from PID reuse race conditions.
9//!
10//! The typical ways to obtain a pidfd include:
11//!
12//! - **Using `clone3` with `CLONE_PIDFD`**: On nightly Rust, use `std::process::Command`
13//! with `create_pidfd(true)` and then call `into_pidfd()` on the child process.
14//! - **Clearing the `CLOEXEC` flag and exec'ing**: Clear the close-on-exec flag using `libc::fcntl`
15//! with `libc::F_SETFD`, then exec the target process.
16//! - **Passing via UNIX socket**: Use `sendmsg`/`recvmsg` on a UNIX socket to pass the file descriptor
17//! between processes. This is exposed in `std::os::unix::net::UnixStream::recv_vectored_with_ancillary`.
18//!
19//! **Warning**: While `PidFd::from_pid()` exists, its use is highly discouraged. There is a race
20//! condition where the process with the PID dies and a new process gets assigned the same recycled PID,
21//! causing the resulting pidfd to refer to the wrong process.
22//!
23//! # Features
24//!
25//! - **Safe process operations**: Send signals, wait for exit, query process information
26//! - **PID reuse protection**: Pidfds remain valid and unique even after process termination
27//! - **Modern kernel support**: Uses modern kernel APIs when available, falls back to older methods
28//! - **Async support**: Optional async operations via the `async` feature (enabled by default)
29//! - **Nightly compatibility**: Uses stdlib's `PidFd` on nightly, provides own implementation on stable
30//!
31//! # Core Types
32//!
33//! - [`PidFd`]: The main type representing a process file descriptor
34//! - [`PidFdExt`]: Extension trait providing additional operations (get PID, credentials, namespaces, etc.)
35//! - [`AsyncPidFd`]: Async wrapper for waiting on process exit (requires `async` feature)
36//! - [`PidFdCreds`]: Process credential information (UID, GID variants)
37//! - [`PidFdGetNamespace`]: Namespace types that can be queried
38//!
39//! # Examples
40//!
41//! ```no_run
42//! # #![cfg_attr(feature = "nightly", feature(linux_pidfd))]
43//! #
44//! # use pidfd_util::{PidFd, PidFdExt};
45//! # #[cfg(feature = "nightly")]
46//! # use std::os::linux::process::{CommandExt, ChildExt};
47//! # use std::process::Command;
48//! #
49//! # #[cfg(feature = "nightly")]
50//! # fn spawn_child() -> PidFd {
51//! # // Spawn a child process with pidfd support
52//! # let mut child = Command::new("echo")
53//! # .create_pidfd(true)
54//! # .spawn()
55//! # .expect("Failed to spawn child");
56//! #
57//! # // Get the pidfd for the child
58//! # child
59//! # .into_pidfd()
60//! # .expect("Failed to retrieve pidfd")
61//! # }
62//! #
63//! # #[cfg(not(feature = "nightly"))]
64//! # fn spawn_child() -> PidFd {
65//! # // Spawn a child process with pidfd support
66//! # let mut child = Command::new("echo")
67//! # .spawn()
68//! # .expect("Failed to spawn child");
69//! #
70//! # // WARNING! This is racy! Don't actually do this!
71//! # PidFd::from_pid(child.id().try_into().unwrap())
72//! # .expect("Failed to retrieve pidfd")
73//! # }
74//! #
75//! # fn main() -> std::io::Result<()> {
76//! let pidfd = spawn_child();
77//! // Query process information
78//! let pid = pidfd.get_pid().expect("Failed to get the child PID");
79//! let creds = pidfd.get_creds().expect("Failed to get child credentials");
80//! println!("Process {} running as UID {}", pid, creds.euid);
81//!
82//! // Send a signal
83//! pidfd.send_signal(libc::SIGTERM).expect("Failed to send SIGTERM to child");
84//!
85//! // Wait for process to exit
86//! let status = pidfd.wait().expect("Failed to wait for child to exit");
87//! println!("Process exited with status: {:?}", status);
88//! # Ok(())
89//! # }
90//! ```
91//!
92//! # Kernel Requirements
93//!
94//! - Basic pidfd support requires Linux 5.3+
95//! - Some operations require newer kernels (automatically detected with fallback where possible)
96
97#![cfg_attr(feature = "nightly", feature(linux_pidfd))]
98
99mod lowlevel;
100#[cfg(feature = "async")]
101mod pidfd_async;
102mod pidfd_ext;
103#[cfg(not(feature = "nightly"))]
104mod pidfd_impl;
105#[cfg(test)]
106mod tests;
107
108#[cfg(not(feature = "nightly"))]
109pub use pidfd_impl::*;
110#[cfg(feature = "nightly")]
111pub use std::os::linux::process::PidFd;
112
113pub use lowlevel::{PidFdCreds, PidFdGetNamespace};
114pub use pidfd_ext::PidFdExt;
115
116#[cfg(feature = "async")]
117pub use pidfd_async::AsyncPidFd;