Safe Rust wrapper for Linux process file descriptors (pidfd).
This crate provides a safe, ergonomic interface to Linux's pidfd API, which represents processes as file descriptors. Unlike traditional PIDs, pidfds cannot be reused after a process exits, making them safe from PID reuse race conditions.
- Safe process operations: Send signals, wait for exit, query process information
- PID reuse protection: Pidfds remain valid and unique even after process termination
- Modern kernel support: Uses modern kernel APIs when available, falls back to older methods
- Async support: Optional async operations via the
asyncfeature (enabled by default) - Nightly compatibility: Uses stdlib's
PidFdon nightly, provides own implementation on stable
Add this to your Cargo.toml:
[dependencies]
pidfd-util = { version = "0.1.0", git = "https://github.com/swick/pidfd-util-rs.git" }
The typical ways to obtain a pidfd include:
- Using
clone3withCLONE_PIDFD: On nightly Rust, usestd::process::Commandwithcreate_pidfd(true)and then callinto_pidfd()on the child process. - Clearing the
CLOEXECflag and exec'ing: Clear the close-on-exec flag usinglibc::fcntlwithlibc::F_SETFD, then exec the target process. - Passing via UNIX socket: Use
sendmsg/recvmsgon a UNIX socket to pass the file descriptor between processes. This is exposed instd::os::unix::net::UnixStream::recv_vectored_with_ancillary.
PidFd::from_pid() exists, its use is highly discouraged. There is a race condition where the process with the PID dies and a new process gets assigned the same recycled PID, causing the resulting pidfd to refer to the wrong process.
use pidfd_util::{PidFd, PidFdExt};
use std::os::linux::process::{CommandExt, ChildExt};
#![feature(linux_pidfd)]
use std::process::Command;
fn main() -> std::io::Result<()> {
// Spawn a child process with pidfd support
let mut child = Command::new("echo")
.create_pidfd(true)
.spawn()
.expect("Failed to spawn child");
// Get the pidfd for the child
let pidfd = child
.into_pidfd()
.expect("Failed to retrieve pidfd");
// Query process information
let pid = pidfd.get_pid().expect("Failed to get the child PID");
let creds = pidfd.get_creds().expect("Failed to get child credentials");
println!("Process {} running as UID {}", pid, creds.euid);
// Send a signal
pidfd.send_signal(libc::SIGTERM).expect("Failed to send SIGTERM to child");
// Wait for process to exit
let status = pidfd.wait().expect("Failed to wait for child to exit");
println!("Process exited with status: {:?}", status);
Ok(())
}
use pidfd_util::{PidFd, PidFdExt, AsyncPidFd};
async fn example(pidfd: PidFd) -> std::io::Result<()> {
let async_pidfd: AsyncPidFd = pidfd.try_into()?;
// Asynchronously wait for the process to exit
let status = async_pidfd.wait().await?;
println!("Process exited with: {:?}", status);
Ok(())
}
PidFd: The main type representing a process file descriptorPidFdExt: Extension trait providing additional operations (get PID, credentials, namespaces, etc.)AsyncPidFd: Async wrapper for waiting on process exit (requiresasyncfeature)PidfdCreds: Process credential information (UID, GID variants)PidfdGetNamespace: Namespace types that can be queried
get_pid()- Get the process ID of the process referred to by the pidfdget_ppid()- Get the parent process IDget_id()- Get a unique, non-reusable process identifier (useful for logging)get_creds()- Get process credentials (UIDs/GIDs)get_cgroupid()- Get the cgroup ID
kill()- Send SIGKILL to the processsend_signal()- Send any signal to the processwait()- Wait for process exit (blocking)try_wait()- Check if process has exited (non-blocking)
get_namespace()- Get a file descriptor to a process namespaceset_namespace()- Move the calling process into a namespace of the target processget_remote_fd()- Duplicate a file descriptor from another processaccess_proc()- Execute a function with PID reuse protection
- Basic pidfd support requires Linux 5.3+
- Some operations require newer kernels (automatically detected with fallback where possible)
async(default): EnablesAsyncPidFdfor async process waitingnightly: Uses stdlib'sPidFdimplementation on nightly Rust
This project is licensed under either of:
- MIT License
- Apache License, Version 2.0
at your option.