mirror of
https://github.com/uutils/procps.git
synced 2026-06-10 16:14:00 -07:00
pmap: implemented show-path option (#418)
* pmap: implemented show-path option
* Fix CI failure caused by zip crate version upgrade
* Revert the previous commit as the problem was solved upstream
This reverts commit 9c2de67f36.
* Refactored regexes in test pmap
This commit is contained in:
@@ -157,9 +157,13 @@ impl MapLine {
|
||||
}
|
||||
}
|
||||
|
||||
match self.mapping.rsplit_once('/') {
|
||||
Some((_, name)) => name.into(),
|
||||
None => self.mapping.clone(),
|
||||
if pmap_config.show_path {
|
||||
self.mapping.clone()
|
||||
} else {
|
||||
match self.mapping.rsplit_once('/') {
|
||||
Some((_, name)) => name.into(),
|
||||
None => self.mapping.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,32 +289,68 @@ mod test {
|
||||
|
||||
mapline.mapping = "".to_string();
|
||||
pmap_config.custom_format_enabled = false;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.custom_format_enabled = true;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!("", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!("", mapline.parse_mapping(&pmap_config));
|
||||
|
||||
mapline.mapping = "[vvar]".to_string();
|
||||
pmap_config.custom_format_enabled = false;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.custom_format_enabled = true;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!("[vvar]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!("[vvar]", mapline.parse_mapping(&pmap_config));
|
||||
|
||||
mapline.mapping = "anon_inode:i915.gem".to_string();
|
||||
pmap_config.custom_format_enabled = false;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.custom_format_enabled = true;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!("anon_inode:i915.gem", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!("anon_inode:i915.gem", mapline.parse_mapping(&pmap_config));
|
||||
|
||||
mapline.mapping = "[stack]".to_string();
|
||||
pmap_config.custom_format_enabled = false;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!(" [ stack ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!(" [ stack ]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.custom_format_enabled = true;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!("[stack]", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!("[stack]", mapline.parse_mapping(&pmap_config));
|
||||
|
||||
mapline.mapping = "/usr/lib/ld-linux-x86-64.so.2".to_string();
|
||||
pmap_config.custom_format_enabled = false;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!("ld-linux-x86-64.so.2", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!(
|
||||
"/usr/lib/ld-linux-x86-64.so.2",
|
||||
mapline.parse_mapping(&pmap_config)
|
||||
);
|
||||
pmap_config.custom_format_enabled = true;
|
||||
pmap_config.show_path = false;
|
||||
assert_eq!("ld-linux-x86-64.so.2", mapline.parse_mapping(&pmap_config));
|
||||
pmap_config.show_path = true;
|
||||
assert_eq!(
|
||||
"/usr/lib/ld-linux-x86-64.so.2",
|
||||
mapline.parse_mapping(&pmap_config)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
pmap_config.set_most_extended();
|
||||
}
|
||||
|
||||
// Options independent with field selection:
|
||||
if matches.get_flag(options::SHOW_PATH) {
|
||||
pmap_config.show_path = true;
|
||||
}
|
||||
|
||||
let pids = matches
|
||||
.get_many::<String>(options::PID)
|
||||
.expect("PID required");
|
||||
|
||||
@@ -72,6 +72,8 @@ pub struct PmapConfig {
|
||||
pub protection_key: bool,
|
||||
pub vmflags: bool,
|
||||
pub mapping: bool,
|
||||
// [Mapping] category
|
||||
pub show_path: bool,
|
||||
// Misc
|
||||
pub custom_format_enabled: bool,
|
||||
}
|
||||
|
||||
+106
-24
@@ -30,7 +30,7 @@ fn test_existing_pid() {
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_format(pid, &result);
|
||||
assert_format(pid, &result, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -50,8 +50,8 @@ fn test_multiple_existing_pids() {
|
||||
let pos_second_pid = result.iter().rposition(|line| re.is_match(line)).unwrap();
|
||||
let (left, right) = result.split_at(pos_second_pid);
|
||||
|
||||
assert_format(pid, &left.join("\n"));
|
||||
assert_format(pid, &right.join("\n"));
|
||||
assert_format(pid, &left.join("\n"), false);
|
||||
assert_format(pid, &right.join("\n"), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -65,7 +65,7 @@ fn test_non_existing_and_existing_pid() {
|
||||
.fails();
|
||||
let result = result.code_is(42).no_stderr().stdout_str();
|
||||
|
||||
assert_format(pid, result);
|
||||
assert_format(pid, result, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -103,7 +103,7 @@ fn test_extended() {
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_extended_format(pid, &result);
|
||||
assert_extended_format(pid, &result, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ fn test_more_extended() {
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_more_extended_format(pid, &result);
|
||||
assert_more_extended_format(pid, &result, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -134,7 +134,7 @@ fn test_most_extended() {
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_most_extended_format(pid, &result);
|
||||
assert_most_extended_format(pid, &result, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -166,7 +166,7 @@ fn test_device() {
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_device_format(pid, &result);
|
||||
assert_device_format(pid, &result, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +187,63 @@ fn test_device_permission_denied() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_showpath() {
|
||||
let pid = process::id();
|
||||
|
||||
for arg in ["-p", "--show-path"] {
|
||||
// default format
|
||||
let result = new_ucmd!()
|
||||
.arg(arg)
|
||||
.arg(pid.to_string())
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_format(pid, &result, true);
|
||||
|
||||
// extended format
|
||||
let result = new_ucmd!()
|
||||
.arg(arg)
|
||||
.arg("--extended")
|
||||
.arg(pid.to_string())
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_extended_format(pid, &result, true);
|
||||
|
||||
// more-extended format
|
||||
let result = new_ucmd!()
|
||||
.arg(arg)
|
||||
.arg("-X")
|
||||
.arg(pid.to_string())
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_more_extended_format(pid, &result, true);
|
||||
|
||||
// most-extended format
|
||||
let result = new_ucmd!()
|
||||
.arg(arg)
|
||||
.arg("--XX")
|
||||
.arg(pid.to_string())
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_most_extended_format(pid, &result, true);
|
||||
|
||||
// device format
|
||||
let result = new_ucmd!()
|
||||
.arg(arg)
|
||||
.arg("--device")
|
||||
.arg(pid.to_string())
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert_device_format(pid, &result, true);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_arg() {
|
||||
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
|
||||
@@ -211,14 +268,20 @@ fn assert_cmdline_only(pid: &str, s: &str) {
|
||||
// ...
|
||||
// total 1040320K
|
||||
#[cfg(target_os = "linux")]
|
||||
fn assert_format(pid: u32, s: &str) {
|
||||
fn assert_format(pid: u32, s: &str, show_path: bool) {
|
||||
let (first_line, rest) = s.split_once('\n').unwrap();
|
||||
let re = Regex::new(&format!("^{pid}: .+[^ ]$")).unwrap();
|
||||
assert!(re.is_match(first_line));
|
||||
|
||||
let rest = rest.trim_end();
|
||||
let (memory_map, last_line) = rest.rsplit_once('\n').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();
|
||||
let base_pattern = r"(?m)^[0-9a-f]{16} +[1-9][0-9]*K (-|r)(-|w)(-|x)(-|s)-";
|
||||
let mapping_pattern = if show_path {
|
||||
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
|
||||
} else {
|
||||
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
|
||||
};
|
||||
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
|
||||
assert!(re.is_match(memory_map));
|
||||
|
||||
let re = Regex::new("^ total +[1-9][0-9]*K$").unwrap();
|
||||
@@ -236,7 +299,7 @@ fn assert_format(pid: u32, s: &str) {
|
||||
// ---------------- ------- ------- ------- (one intentional trailing space)
|
||||
// total kB 144 7 14
|
||||
#[cfg(target_os = "linux")]
|
||||
fn assert_extended_format(pid: u32, s: &str) {
|
||||
fn assert_extended_format(pid: u32, s: &str, show_path: bool) {
|
||||
let lines: Vec<_> = s.lines().collect();
|
||||
let line_count = lines.len();
|
||||
|
||||
@@ -246,10 +309,13 @@ fn assert_extended_format(pid: u32, s: &str) {
|
||||
let expected_header = "Address Kbytes RSS Dirty Mode Mapping";
|
||||
assert_eq!(expected_header, lines[1], "failing line: '{}'", lines[1]);
|
||||
|
||||
let re = Regex::new(
|
||||
r"^[0-9a-f]{16} +[1-9][0-9]* +\d+ +\d+ (-|r)(-|w)(-|x)(-|s)- ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$",
|
||||
)
|
||||
.unwrap();
|
||||
let base_pattern = r"^[0-9a-f]{16} +[1-9][0-9]* +\d+ +\d+ (-|r)(-|w)(-|x)(-|s)-";
|
||||
let mapping_pattern = if show_path {
|
||||
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
|
||||
} else {
|
||||
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
|
||||
};
|
||||
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
|
||||
|
||||
for line in lines.iter().take(line_count - 2).skip(2) {
|
||||
assert!(re.is_match(line), "failing line: '{line}'");
|
||||
@@ -282,7 +348,7 @@ fn assert_extended_format(pid: u32, s: &str) {
|
||||
// ==== ==== ==== ========= ========== ========= ======== ============== ============= ============== =============== ==== ======= ====== =========== (one intentional trailing space)
|
||||
// 4164 3448 2826 552 3448 552 0 0 0 0 0 0 0 0 0 KB (one intentional trailing space)
|
||||
#[cfg(target_os = "linux")]
|
||||
fn assert_more_extended_format(pid: u32, s: &str) {
|
||||
fn assert_more_extended_format(pid: u32, s: &str, show_path: bool) {
|
||||
let lines: Vec<_> = s.lines().collect();
|
||||
let line_count = lines.len();
|
||||
|
||||
@@ -292,7 +358,13 @@ fn assert_more_extended_format(pid: u32, s: &str) {
|
||||
let re = Regex::new(r"^ Address Perm Offset Device Inode +Size +Rss +Pss +Pss_Dirty +Referenced +Anonymous( +KSM)? +LazyFree +ShmemPmdMapped +FilePmdMapped +Shared_Hugetlb +Private_Hugetlb +Swap +SwapPss +Locked +THPeligible( +ProtectionKey)? +Mapping$").unwrap();
|
||||
assert!(re.is_match(lines[1]), "failing line: '{}'", lines[1]);
|
||||
|
||||
let re = Regex::new(r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? (|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$").unwrap();
|
||||
let base_pattern = r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)?";
|
||||
let mapping_pattern = if show_path {
|
||||
r" (|\[[a-zA-Z_ ]+\]|/[/a-zA-Z0-9._-]+)$"
|
||||
} else {
|
||||
r" (|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$"
|
||||
};
|
||||
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
|
||||
|
||||
for line in lines.iter().take(line_count - 2).skip(2) {
|
||||
assert!(re.is_match(line), "failing line: '{line}'");
|
||||
@@ -324,7 +396,7 @@ fn assert_more_extended_format(pid: u32, s: &str) {
|
||||
// ==== ============== =========== ==== ==== ========= ============ ============ ============= ============= ========== ========= ======== ============= ============== ============= ============== =============== ==== ======= ====== =========== (one intentional trailing space)
|
||||
// 4164 92 92 3448 2880 552 1132 0 1764 552 3448 552 0 0 0 0 0 0 0 0 0 0 KB (one intentional trailing space)
|
||||
#[cfg(target_os = "linux")]
|
||||
fn assert_most_extended_format(pid: u32, s: &str) {
|
||||
fn assert_most_extended_format(pid: u32, s: &str, show_path: bool) {
|
||||
let lines: Vec<_> = s.lines().collect();
|
||||
let line_count = lines.len();
|
||||
|
||||
@@ -334,7 +406,13 @@ fn assert_most_extended_format(pid: u32, s: &str) {
|
||||
let re = Regex::new(r"^ Address Perm Offset Device Inode +Size +KernelPageSize +MMUPageSize +Rss +Pss +Pss_Dirty +Shared_Clean +Shared_Dirty +Private_Clean +Private_Dirty +Referenced +Anonymous( +KSM)? +LazyFree +AnonHugePages +ShmemPmdMapped +FilePmdMapped +Shared_Hugetlb +Private_Hugetlb +Swap +SwapPss +Locked +THPeligible( +ProtectionKey)? +VmFlags +Mapping$").unwrap();
|
||||
assert!(re.is_match(lines[1]), "failing line: '{}'", lines[1]);
|
||||
|
||||
let re = Regex::new(r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +([a-z][a-z] )*(|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$").unwrap();
|
||||
let base_pattern = r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +([a-z][a-z] )*";
|
||||
let mapping_pattern = if show_path {
|
||||
r"(|\[[a-zA-Z_ ]+\]|/[/a-zA-Z0-9._-]+)$"
|
||||
} else {
|
||||
r"(|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$"
|
||||
};
|
||||
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
|
||||
|
||||
for line in lines.iter().take(line_count - 2).skip(2) {
|
||||
assert!(re.is_match(line), "failing line: '{line}'");
|
||||
@@ -365,7 +443,7 @@ fn assert_most_extended_format(pid: u32, s: &str) {
|
||||
// ...
|
||||
// mapped: 3060K writeable/private: 348K shared: 0K
|
||||
#[cfg(target_os = "linux")]
|
||||
fn assert_device_format(pid: u32, s: &str) {
|
||||
fn assert_device_format(pid: u32, s: &str, show_path: bool) {
|
||||
let lines: Vec<_> = s.lines().collect();
|
||||
let line_count = lines.len();
|
||||
|
||||
@@ -375,10 +453,14 @@ fn assert_device_format(pid: u32, s: &str) {
|
||||
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();
|
||||
let base_pattern =
|
||||
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}";
|
||||
let mapping_pattern = if show_path {
|
||||
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
|
||||
} else {
|
||||
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
|
||||
};
|
||||
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
|
||||
|
||||
for line in lines.iter().take(line_count - 1).skip(2) {
|
||||
assert!(re.is_match(line), "failing line: {line}");
|
||||
|
||||
Reference in New Issue
Block a user