pmap: fixed to hide the header when permission is denied (#378)

* pmap: fixed to hide the header when permission is denied

* pmap: fixed lint error
This commit is contained in:
estodi
2025-03-30 09:39:07 -07:00
committed by GitHub
parent c9861a14db
commit 35dad8d767
2 changed files with 111 additions and 39 deletions
+51 -39
View File
@@ -81,13 +81,17 @@ fn parse_cmdline(pid: &str) -> Result<String, Error> {
Ok(cmdline.into())
}
fn process_maps<F>(pid: &str, mut process_line: F) -> Result<(), Error>
fn process_maps<F>(pid: &str, header: Option<&str>, mut process_line: F) -> Result<(), Error>
where
F: FnMut(&MapLine),
{
let path = format!("/proc/{pid}/maps");
let contents = fs::read_to_string(path)?;
if let Some(header) = header {
println!("{header}");
}
for line in contents.lines() {
let map_line = parse_map_line(line)?;
process_line(&map_line);
@@ -96,7 +100,7 @@ where
Ok(())
}
fn process_smaps<F>(pid: &str, mut process_entry: F) -> Result<(), Error>
fn process_smaps<F>(pid: &str, header: Option<&str>, mut process_entry: F) -> Result<(), Error>
where
F: FnMut(&SmapEntry),
{
@@ -104,6 +108,10 @@ where
let contents = fs::read_to_string(path)?;
let smap_entries = parse_smap_entries(&contents)?;
if let Some(header) = header {
println!("{header}");
}
for entry in smap_entries {
process_entry(&entry);
}
@@ -114,7 +122,7 @@ where
fn output_default_format(pid: &str) -> Result<(), Error> {
let mut total = 0;
process_maps(pid, |map_line| {
process_maps(pid, None, |map_line| {
println!(
"{} {:>6}K {} {}",
map_line.address, map_line.size_in_kb, map_line.perms, map_line.mapping
@@ -132,22 +140,24 @@ fn output_extended_format(pid: &str) -> Result<(), Error> {
let mut total_rss = 0;
let mut total_dirty = 0;
println!("Address Kbytes RSS Dirty Mode Mapping");
process_smaps(pid, |smap_entry| {
println!(
"{} {:>7} {:>7} {:>7} {} {}",
smap_entry.map_line.address,
smap_entry.map_line.size_in_kb,
smap_entry.rss_in_kb,
smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb,
smap_entry.map_line.perms,
smap_entry.map_line.mapping
);
total_mapped += smap_entry.map_line.size_in_kb;
total_rss += smap_entry.rss_in_kb;
total_dirty += smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb;
})?;
process_smaps(
pid,
Some("Address Kbytes RSS Dirty Mode Mapping"),
|smap_entry| {
println!(
"{} {:>7} {:>7} {:>7} {} {}",
smap_entry.map_line.address,
smap_entry.map_line.size_in_kb,
smap_entry.rss_in_kb,
smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb,
smap_entry.map_line.perms,
smap_entry.map_line.mapping
);
total_mapped += smap_entry.map_line.size_in_kb;
total_rss += smap_entry.rss_in_kb;
total_dirty += smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb;
},
)?;
println!("---------------- ------- ------- ------- ");
println!("total kB {total_mapped:>7} {total_rss:>7} {total_dirty:>7}");
@@ -160,28 +170,30 @@ fn output_device_format(pid: &str) -> Result<(), Error> {
let mut total_writeable_private = 0;
let mut total_shared = 0;
println!("Address Kbytes Mode Offset Device Mapping");
process_maps(
pid,
Some("Address Kbytes Mode Offset Device Mapping"),
|map_line| {
println!(
"{} {:>7} {} {} {} {}",
map_line.address,
map_line.size_in_kb,
map_line.perms,
map_line.offset,
map_line.device,
map_line.mapping
);
total_mapped += map_line.size_in_kb;
process_maps(pid, |map_line| {
println!(
"{} {:>7} {} {} {} {}",
map_line.address,
map_line.size_in_kb,
map_line.perms,
map_line.offset,
map_line.device,
map_line.mapping
);
total_mapped += map_line.size_in_kb;
if map_line.perms.writable && !map_line.perms.shared {
total_writeable_private += map_line.size_in_kb;
}
if map_line.perms.writable && !map_line.perms.shared {
total_writeable_private += map_line.size_in_kb;
}
if map_line.perms.shared {
total_shared += map_line.size_in_kb;
}
})?;
if map_line.perms.shared {
total_shared += map_line.size_in_kb;
}
},
)?;
println!(
"mapped: {total_mapped}K writeable/private: {total_writeable_private}K shared: {total_shared}K"
+60
View File
@@ -10,6 +10,8 @@ use regex::Regex;
use std::process;
const NON_EXISTING_PID: &str = "999999";
#[cfg(target_os = "linux")]
const INIT_PID: &str = "1";
#[test]
fn test_no_args() {
@@ -73,6 +75,20 @@ fn test_non_existing_pid() {
.no_output();
}
#[test]
#[cfg(target_os = "linux")]
fn test_permission_denied() {
let result = new_ucmd!()
.arg(INIT_PID)
.fails()
.code_is(1)
.no_stderr()
.clone()
.stdout_move_str();
assert_cmdline_only(INIT_PID, &result);
}
#[test]
#[cfg(target_os = "linux")]
fn test_extended() {
@@ -89,6 +105,23 @@ fn test_extended() {
}
}
#[test]
#[cfg(target_os = "linux")]
fn test_extended_permission_denied() {
for arg in ["-x", "--extended"] {
let result = new_ucmd!()
.arg(arg)
.arg(INIT_PID)
.fails()
.code_is(1)
.no_stderr()
.clone()
.stdout_move_str();
assert_cmdline_only(INIT_PID, &result);
}
}
#[test]
#[cfg(target_os = "linux")]
fn test_device() {
@@ -105,11 +138,38 @@ fn test_device() {
}
}
#[test]
#[cfg(target_os = "linux")]
fn test_device_permission_denied() {
for arg in ["-d", "--device"] {
let result = new_ucmd!()
.arg(arg)
.arg(INIT_PID)
.fails()
.code_is(1)
.no_stderr()
.clone()
.stdout_move_str();
assert_cmdline_only(INIT_PID, &result);
}
}
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}
// Ensure `s` has the following format:
//
// 1234: /some/path
#[cfg(target_os = "linux")]
fn assert_cmdline_only(pid: &str, s: &str) {
let s = s.trim_end();
let re = Regex::new(&format!("^{pid}: .+[^ ]$")).unwrap();
assert!(re.is_match(s));
}
// Ensure `s` has the following format:
//
// 1234: /some/path