Skip to content

Commit 05da8c1

Browse files
committed
pmap: fixed to hide the header when permission is denied
1 parent 46c2a0a commit 05da8c1

File tree

2 files changed

+111
-40
lines changed

2 files changed

+111
-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: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use regex::Regex;
99
#[cfg(target_os = "linux")]
1010
use std::process;
1111

12+
const INIT_PID: &str = "1";
1213
const NON_EXISTING_PID: &str = "999999";
1314

1415
#[test]
@@ -73,6 +74,20 @@ fn test_non_existing_pid() {
7374
.no_output();
7475
}
7576

77+
#[test]
78+
#[cfg(target_os = "linux")]
79+
fn test_permission_denied() {
80+
let result = new_ucmd!()
81+
.arg(INIT_PID)
82+
.fails()
83+
.code_is(1)
84+
.no_stderr()
85+
.clone()
86+
.stdout_move_str();
87+
88+
assert_cmdline_only(INIT_PID, &result);
89+
}
90+
7691
#[test]
7792
#[cfg(target_os = "linux")]
7893
fn test_extended() {
@@ -89,6 +104,23 @@ fn test_extended() {
89104
}
90105
}
91106

107+
#[test]
108+
#[cfg(target_os = "linux")]
109+
fn test_extended_permission_denied() {
110+
for arg in ["-x", "--extended"] {
111+
let result = new_ucmd!()
112+
.arg(arg)
113+
.arg(INIT_PID)
114+
.fails()
115+
.code_is(1)
116+
.no_stderr()
117+
.clone()
118+
.stdout_move_str();
119+
120+
assert_cmdline_only(INIT_PID, &result);
121+
}
122+
}
123+
92124
#[test]
93125
#[cfg(target_os = "linux")]
94126
fn test_device() {
@@ -105,11 +137,38 @@ fn test_device() {
105137
}
106138
}
107139

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

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

0 commit comments

Comments
 (0)