Skip to content

Commit

Permalink
pmap: implement --device
Browse files Browse the repository at this point in the history
  • Loading branch information
cakebaker committed Oct 9, 2024
1 parent 7ab7635 commit 700bd50
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 8 deletions.
55 changes: 48 additions & 7 deletions src/uu/pmap/src/pmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}
}

match parse_maps(pid) {
Ok(total) => println!(" total {total:>16}K"),
Err(_) => {
set_exit_code(1);
}
if matches.get_flag(options::DEVICE) {
output_device_format(pid).map_err(|_| set_exit_code(1)).ok();
} else {
output_default_format(pid)
.map_err(|_| set_exit_code(1))

Check warning on line 56 in src/uu/pmap/src/pmap.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/pmap/src/pmap.rs#L56

Added line #L56 was not covered by tests
.ok();
}
}

Expand All @@ -74,7 +75,7 @@ fn parse_cmdline(pid: &str) -> Result<String, Error> {
Ok(cmdline.into())
}

fn parse_maps(pid: &str) -> Result<u64, Error> {
fn output_default_format(pid: &str) -> Result<(), Error> {
let path = format!("/proc/{pid}/maps");
let contents = fs::read_to_string(path)?;
let mut total = 0;
Expand All @@ -88,7 +89,47 @@ fn parse_maps(pid: &str) -> Result<u64, Error> {
total += map_line.size_in_kb;
}

Ok(total)
println!(" total {total:>16}K");

Ok(())
}

fn output_device_format(pid: &str) -> Result<(), Error> {
let path = format!("/proc/{pid}/maps");
let contents = fs::read_to_string(path)?;
let mut total_mapped = 0;
let mut total_writeable_private = 0;
let mut total_shared = 0;

println!("Address Kbytes Mode Offset Device Mapping");

for line in contents.lines() {
let map_line = parse_map_line(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.shared {
total_shared += map_line.size_in_kb;

Check warning on line 124 in src/uu/pmap/src/pmap.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/pmap/src/pmap.rs#L124

Added line #L124 was not covered by tests
}
}

println!(
"mapped: {total_mapped}K writeable/private: {total_writeable_private}K shared: {total_shared}K"
);

Ok(())
}

pub fn uu_app() -> Command {
Expand Down
55 changes: 54 additions & 1 deletion tests/by-util/test_pmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ fn test_non_existing_pid() {
.no_output();
}

#[test]
#[cfg(target_os = "linux")]
fn test_device() {
let pid = process::id();

for arg in ["-d", "--device"] {
let result = new_ucmd!()
.arg(arg)
.arg(pid.to_string())
.succeeds()
.stdout_move_str();

assert_device_format(pid, &result);
}
}

#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
Expand All @@ -94,9 +110,46 @@ fn assert_format(pid: u32, s: &str) {

let rest = rest.trim_end();
let (memory_map, last_line) = rest.rsplit_once('\n').unwrap();
let re = Regex::new("(?m)^[0-9a-f]{16} +[1-9][0-9]*K (-|r)(-|w)(-|x)(-|s)- ( $$[ (anon|stack) $$]|[a-zA-Z0-9._-]+)$").unwrap();
let re = Regex::new(r"(?m)^[0-9a-f]{16} +[1-9][0-9]*K (-|r)(-|w)(-|x)(-|s)- ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$").unwrap();
assert!(re.is_match(memory_map));

let re = Regex::new("^ total +[1-9][0-9]*K$").unwrap();
assert!(re.is_match(last_line));
}

// Ensure `s` has the following device format (--device):
//
// 1234: /some/path
// Address Kbytes Mode Offset Device Mapping
// 000073eb5f4c7000 8 rw--- 0000000000036000 008:00008 ld-linux-x86-64.so.2
// 00007ffd588fc000 132 rw--- 0000000000000000 000:00000 [ stack ]
// ffffffffff600000 4 --x-- 0000000000000000 000:00000 [ anon ]
// ...
// mapped: 3060K writeable/private: 348K shared: 0K
#[cfg(target_os = "linux")]
fn assert_device_format(pid: u32, s: &str) {
let lines: Vec<_> = s.lines().collect();
let index_last_line = lines.len() - 1;

let re = Regex::new(&format!("^{pid}: .+[^ ]$")).unwrap();
assert!(re.is_match(lines[0]));

let expected_header = "Address Kbytes Mode Offset Device Mapping";
assert_eq!(expected_header, lines[1]);

let re = Regex::new(
r"^[0-9a-f]{16} +[1-9][0-9]* (-|r)(-|w)(-|x)(-|s)- [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$",
)
.unwrap();

for i in 2..index_last_line {
assert!(re.is_match(lines[i]), "failing line: {}", lines[i]);
}

let re = Regex::new(r"^mapped: \d+K\s{4}writeable/private: \d+K\s{4}shared: \d+K$").unwrap();
assert!(

Check warning on line 150 in tests/by-util/test_pmap.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_pmap.rs#L150

Added line #L150 was not covered by tests
re.is_match(lines[index_last_line]),
"failing line: {}",
lines[index_last_line]

Check warning on line 153 in tests/by-util/test_pmap.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_pmap.rs#L153

Added line #L153 was not covered by tests
);
}

0 comments on commit 700bd50

Please sign in to comment.