pgrep: optimize get Namespace via statx syscall

This commit is contained in:
Krysztal Huang
2025-11-08 03:25:59 +08:00
parent f40f58880a
commit 7d94174992
4 changed files with 68 additions and 38 deletions
Generated
+13 -12
View File
@@ -289,7 +289,7 @@ dependencies = [
"document-features",
"mio",
"parking_lot",
"rustix 1.0.5",
"rustix 1.1.2",
"signal-hook",
"signal-hook-mio",
"winapi",
@@ -772,7 +772,7 @@ dependencies = [
"portable-atomic",
"portable-atomic-util",
"serde_core",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -841,9 +841,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litrs"
@@ -1142,7 +1142,7 @@ dependencies = [
"chrono",
"flate2",
"procfs-core",
"rustix 1.0.5",
"rustix 1.1.2",
]
[[package]]
@@ -1359,15 +1359,15 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.0.5"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.9.4",
"windows-sys 0.59.0",
"linux-raw-sys 0.11.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -1570,7 +1570,7 @@ dependencies = [
"fastrand",
"getrandom 0.3.2",
"once_cell",
"rustix 1.0.5",
"rustix 1.1.2",
"windows-sys 0.61.2",
]
@@ -1591,7 +1591,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
dependencies = [
"rustix 1.0.5",
"rustix 1.1.2",
"windows-sys 0.60.2",
]
@@ -1805,6 +1805,7 @@ version = "0.0.1"
dependencies = [
"clap",
"regex",
"rustix 1.1.2",
"uucore 0.2.2",
"walkdir",
]
@@ -2564,7 +2565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
dependencies = [
"libc",
"rustix 1.0.5",
"rustix 1.1.2",
]
[[package]]
+1
View File
@@ -69,6 +69,7 @@ prettytable-rs = "0.10.0"
rand = { version = "0.9.0", features = ["small_rng"] }
ratatui = "0.29.0"
regex = "1.10.4"
rustix = { version = "1.1.2", features = ["fs"] }
sysinfo = "0.37.0"
tempfile = "3.10.1"
terminal_size = "0.4.2"
+3 -2
View File
@@ -14,10 +14,11 @@ version.workspace = true
workspace = true
[dependencies]
uucore = { workspace = true, features = ["entries", "signals", "process"] }
clap = { workspace = true }
walkdir = { workspace = true }
regex = { workspace = true }
rustix = { workspace = true }
uucore = { workspace = true, features = ["entries", "signals", "process"] }
walkdir = { workspace = true }
[lib]
path = "src/pgrep.rs"
+51 -24
View File
@@ -218,15 +218,19 @@ impl TryFrom<&str> for CgroupMembership {
}
}
// See https://www.man7.org/linux/man-pages/man7/namespaces.7.html
/// See https://www.man7.org/linux/man-pages/man7/namespaces.7.html
///
/// # Support status
///
/// **_Linux only._**
#[derive(Default)]
pub struct Namespace {
pub ipc: Option<String>,
pub mnt: Option<String>,
pub net: Option<String>,
pub pid: Option<String>,
pub user: Option<String>,
pub uts: Option<String>,
pub ipc: Option<u64>,
pub mnt: Option<u64>,
pub net: Option<u64>,
pub pid: Option<u64>,
pub user: Option<u64>,
pub uts: Option<u64>,
}
impl Namespace {
@@ -241,28 +245,51 @@ impl Namespace {
}
}
pub fn from_pid(pid: usize) -> Result<Self, io::Error> {
let mut ns = Namespace::new();
let path = PathBuf::from(format!("/proc/{pid}/ns"));
for entry in fs::read_dir(path)? {
let entry = entry?;
if let Some(name) = entry.file_name().to_str() {
if let Ok(value) = read_link(entry.path()) {
match name {
"ipc" => ns.ipc = Some(value.to_str().unwrap_or_default().to_string()),
"mnt" => ns.mnt = Some(value.to_str().unwrap_or_default().to_string()),
"net" => ns.net = Some(value.to_str().unwrap_or_default().to_string()),
"pid" => ns.pid = Some(value.to_str().unwrap_or_default().to_string()),
"user" => ns.user = Some(value.to_str().unwrap_or_default().to_string()),
"uts" => ns.uts = Some(value.to_str().unwrap_or_default().to_string()),
_ => {}
}
}
#[cfg(target_os = "linux")]
pub fn from_pid(pid: usize) -> io::Result<Self> {
use std::os::fd::OwnedFd;
use rustix::fs::{openat, statx, AtFlags, Mode, OFlags, StatxFlags, CWD};
let f = |name: &str, fd: &OwnedFd| {
statx(
fd,
name,
AtFlags::empty(), // NO FOLLOW LINKS
StatxFlags::INO, // INNODE ONLY
)
};
let ns_dir = openat(
CWD,
PathBuf::from(format!("/proc/{}/ns", pid)),
OFlags::RDONLY | OFlags::CLOEXEC,
Mode::empty(),
)?;
let mut ns = Namespace::default();
for (name, slot) in [
("ipc", &mut ns.ipc),
("mnt", &mut ns.mnt),
("net", &mut ns.net),
("pid", &mut ns.pid),
("user", &mut ns.user),
("uts", &mut ns.uts),
] {
match f(name, &ns_dir) {
Ok(st) => *slot = Some(st.stx_ino),
Err(e) => return Err(e.into()),
}
}
Ok(ns)
}
/// TODO: implementation for other system
#[cfg(not(target_os = "linux"))]
pub fn from_pid(_pid: usize) -> Result<Self, io::Error> {
Ok(Namespace::new())
}
pub fn filter(&mut self, filters: &[&str]) {
if !filters.contains(&"ipc") {
self.ipc = None;