Skip to content

Commit 35dad8d

Browse files
authored
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
1 parent c9861a1 commit 35dad8d

File tree

2 files changed

+112
-40
lines changed

2 files changed

+112
-40
lines changed

src/uu/pmap/src/pmap.rs

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,17 @@ fn parse_cmdline(pid: &str) -> Result<String, Error> {
8181
Ok(cmdline.into())
8282
}
8383

84-
fn process_maps<F>(pid: &str, mut process_line: F) -> Result<(), Error>
84+
fn process_maps<F>(pid: &str, header: Option<&str>, mut process_line: F) -> Result<(), Error>
8585
where
8686
F: FnMut(&MapLine),
8787
{
8888
let path = format!("/proc/{pid}/maps");
8989
let contents = fs::read_to_string(path)?;
9090

91+
if let Some(header) = header {
92+
println!("{header}");
93+
}
94+
9195
for line in contents.lines() {
9296
let map_line = parse_map_line(line)?;
9397
process_line(&map_line);
@@ -96,14 +100,18 @@ where
96100
Ok(())
97101
}
98102

99-
fn process_smaps<F>(pid: &str, mut process_entry: F) -> Result<(), Error>
103+
fn process_smaps<F>(pid: &str, header: Option<&str>, mut process_entry: F) -> Result<(), Error>
100104
where
101105
F: FnMut(&SmapEntry),
102106
{
103107
let path = format!("/proc/{pid}/smaps");
104108
let contents = fs::read_to_string(path)?;
105109
let smap_entries = parse_smap_entries(&contents)?;
106110

111+
if let Some(header) = header {
112+
println!("{header}");
113+
}
114+
107115
for entry in smap_entries {
108116
process_entry(&entry);
109117
}
@@ -114,7 +122,7 @@ where
114122
fn output_default_format(pid: &str) -> Result<(), Error> {
115123
let mut total = 0;
116124

117-
process_maps(pid, |map_line| {
125+
process_maps(pid, None, |map_line| {
118126
println!(
119127
"{} {:>6}K {} {}",
120128
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> {
132140
let mut total_rss = 0;
133141
let mut total_dirty = 0;
134142

135-
println!("Address Kbytes RSS Dirty Mode Mapping");
136-
137-
process_smaps(pid, |smap_entry| {
138-
println!(
139-
"{} {:>7} {:>7} {:>7} {} {}",
140-
smap_entry.map_line.address,
141-
smap_entry.map_line.size_in_kb,
142-
smap_entry.rss_in_kb,
143-
smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb,
144-
smap_entry.map_line.perms,
145-
smap_entry.map_line.mapping
146-
);
147-
total_mapped += smap_entry.map_line.size_in_kb;
148-
total_rss += smap_entry.rss_in_kb;
149-
total_dirty += smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb;
150-
})?;
143+
process_smaps(
144+
pid,
145+
Some("Address Kbytes RSS Dirty Mode Mapping"),
146+
|smap_entry| {
147+
println!(
148+
"{} {:>7} {:>7} {:>7} {} {}",
149+
smap_entry.map_line.address,
150+
smap_entry.map_line.size_in_kb,
151+
smap_entry.rss_in_kb,
152+
smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb,
153+
smap_entry.map_line.perms,
154+
smap_entry.map_line.mapping
155+
);
156+
total_mapped += smap_entry.map_line.size_in_kb;
157+
total_rss += smap_entry.rss_in_kb;
158+
total_dirty += smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb;
159+
},
160+
)?;
151161

152162
println!("---------------- ------- ------- ------- ");
153163
println!("total kB {total_mapped:>7} {total_rss:>7} {total_dirty:>7}");
@@ -160,28 +170,30 @@ fn output_device_format(pid: &str) -> Result<(), Error> {
160170
let mut total_writeable_private = 0;
161171
let mut total_shared = 0;
162172

163-
println!("Address Kbytes Mode Offset Device Mapping");
164-
165-
process_maps(pid, |map_line| {
166-
println!(
167-
"{} {:>7} {} {} {} {}",
168-
map_line.address,
169-
map_line.size_in_kb,
170-
map_line.perms,
171-
map_line.offset,
172-
map_line.device,
173-
map_line.mapping
174-
);
175-
total_mapped += map_line.size_in_kb;
176-
177-
if map_line.perms.writable && !map_line.perms.shared {
178-
total_writeable_private += map_line.size_in_kb;
179-
}
173+
process_maps(
174+
pid,
175+
Some("Address Kbytes Mode Offset Device Mapping"),
176+
|map_line| {
177+
println!(
178+
"{} {:>7} {} {} {} {}",
179+
map_line.address,
180+
map_line.size_in_kb,
181+
map_line.perms,
182+
map_line.offset,
183+
map_line.device,
184+
map_line.mapping
185+
);
186+
total_mapped += map_line.size_in_kb;
187+
188+
if map_line.perms.writable && !map_line.perms.shared {
189+
total_writeable_private += map_line.size_in_kb;
190+
}
180191

181-
if map_line.perms.shared {
182-
total_shared += map_line.size_in_kb;
183-
}
184-
})?;
192+
if map_line.perms.shared {
193+
total_shared += map_line.size_in_kb;
194+
}
195+
},
196+
)?;
185197

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

tests/by-util/test_pmap.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use regex::Regex;
1010
use std::process;
1111

1212
const NON_EXISTING_PID: &str = "999999";
13+
#[cfg(target_os = "linux")]
14+
const INIT_PID: &str = "1";
1315

1416
#[test]
1517
fn test_no_args() {
@@ -73,6 +75,20 @@ fn test_non_existing_pid() {
7375
.no_output();
7476
}
7577

78+
#[test]
79+
#[cfg(target_os = "linux")]
80+
fn test_permission_denied() {
81+
let result = new_ucmd!()
82+
.arg(INIT_PID)
83+
.fails()
84+
.code_is(1)
85+
.no_stderr()
86+
.clone()
87+
.stdout_move_str();
88+
89+
assert_cmdline_only(INIT_PID, &result);
90+
}
91+
7692
#[test]
7793
#[cfg(target_os = "linux")]
7894
fn test_extended() {
@@ -89,6 +105,23 @@ fn test_extended() {
89105
}
90106
}
91107

108+
#[test]
109+
#[cfg(target_os = "linux")]
110+
fn test_extended_permission_denied() {
111+
for arg in ["-x", "--extended"] {
112+
let result = new_ucmd!()
113+
.arg(arg)
114+
.arg(INIT_PID)
115+
.fails()
116+
.code_is(1)
117+
.no_stderr()
118+
.clone()
119+
.stdout_move_str();
120+
121+
assert_cmdline_only(INIT_PID, &result);
122+
}
123+
}
124+
92125
#[test]
93126
#[cfg(target_os = "linux")]
94127
fn test_device() {
@@ -105,11 +138,38 @@ fn test_device() {
105138
}
106139
}
107140

141+
#[test]
142+
#[cfg(target_os = "linux")]
143+
fn test_device_permission_denied() {
144+
for arg in ["-d", "--device"] {
145+
let result = new_ucmd!()
146+
.arg(arg)
147+
.arg(INIT_PID)
148+
.fails()
149+
.code_is(1)
150+
.no_stderr()
151+
.clone()
152+
.stdout_move_str();
153+
154+
assert_cmdline_only(INIT_PID, &result);
155+
}
156+
}
157+
108158
#[test]
109159
fn test_invalid_arg() {
110160
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
111161
}
112162

163+
// Ensure `s` has the following format:
164+
//
165+
// 1234: /some/path
166+
#[cfg(target_os = "linux")]
167+
fn assert_cmdline_only(pid: &str, s: &str) {
168+
let s = s.trim_end();
169+
let re = Regex::new(&format!("^{pid}: .+[^ ]$")).unwrap();
170+
assert!(re.is_match(s));
171+
}
172+
113173
// Ensure `s` has the following format:
114174
//
115175
// 1234: /some/path

0 commit comments

Comments
 (0)