Skip to content

Commit b79265c

Browse files
committed
add pidfd_open(2)
1 parent bf1d0e9 commit b79265c

5 files changed

Lines changed: 80 additions & 0 deletions

File tree

changelog/2748.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `pidfd_open(2)`

src/sys/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ feature! {
6363
pub mod personality;
6464
}
6565

66+
#[cfg(target_os = "linux")]
67+
feature! {
68+
#![feature = "process"]
69+
pub mod pidfd;
70+
}
71+
6672
#[cfg(target_os = "linux")]
6773
feature! {
6874
#![feature = "process"]

src/sys/pidfd.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//! PID file descriptor APIs.
2+
3+
use std::{
4+
hint::unreachable_unchecked,
5+
os::fd::{FromRawFd as _, OwnedFd, RawFd},
6+
};
7+
8+
use bitflags::bitflags;
9+
10+
use crate::{errno::Errno, unistd::Pid};
11+
12+
bitflags! {
13+
/// Flags for [`pidfd_open`].
14+
#[derive(Copy, Clone)]
15+
pub struct PidfdOpenFlags: libc::c_uint {
16+
/// See [`pidfd_open(2)`] for details.
17+
///
18+
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
19+
const PIDFD_NONBLOCK = libc::PIDFD_NONBLOCK;
20+
21+
/// See [`pidfd_open(2)`] for details.
22+
///
23+
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
24+
const PIDFD_THREAD = libc::PIDFD_THREAD;
25+
}
26+
}
27+
28+
/// Open a PIDFD of the provided PID.
29+
///
30+
/// See [`pidfd_open(2)`] for details.
31+
///
32+
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
33+
///
34+
/// # Safety
35+
///
36+
/// This can race with the PID in `pid` getting released or recycled, unless the
37+
/// PID is that of the calling process, in which case the only way a race could
38+
/// happen is if the current process exits.
39+
///
40+
/// This function is [async-signal-safe], although it may modify `errno`.
41+
///
42+
/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html
43+
pub fn pidfd_open(pid: Pid, flags: PidfdOpenFlags) -> Result<OwnedFd, Errno> {
44+
// SAFETY:
45+
//
46+
// * Arguments passed to the syscall have the correct types.
47+
// * The kernel should not return a value that cannot fit in `RawFd`.
48+
// * The file descriptor returned by the kernel is open, owned, and requires
49+
// only `close` to release its resources.
50+
// * The kernel should not return any negative value other than `-1`.
51+
unsafe {
52+
match libc::syscall(libc::SYS_pidfd_open, pid.as_raw(), flags.bits()) {
53+
fd if fd >= 0 => {
54+
Ok(OwnedFd::from_raw_fd(RawFd::try_from(fd).unwrap_unchecked()))
55+
}
56+
-1 => Err(Errno::last()),
57+
_ => unreachable_unchecked(),
58+
}
59+
}
60+
}

test/sys/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,6 @@ mod test_resource;
9696
// only enable this for FreeBSD for now.
9797
#[cfg(target_os = "freebsd")]
9898
mod test_memfd;
99+
100+
#[cfg(all(target_os = "linux", feature = "process"))]
101+
mod test_pidfd;

test/sys/test_pidfd.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use nix::{
2+
sys::pidfd::{pidfd_open, PidfdOpenFlags},
3+
unistd::getpid,
4+
};
5+
6+
#[test]
7+
fn test_pidfd_open() {
8+
pidfd_open(getpid(), PidfdOpenFlags::empty())
9+
.expect("should be able to get pidfd");
10+
}

0 commit comments

Comments
 (0)