Skip to content

Commit e777f8d

Browse files
authored
Improve error handling in print_files (#10)
Handle errors in print_files that can cause pfiles to panic if a file descriptor is closed while it is iterating over /proc/[pid]/fd/.
1 parent 31fbb25 commit e777f8d

File tree

2 files changed

+41
-14
lines changed

2 files changed

+41
-14
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ name = "netlink_example"
2828
path = "src/bin/testing/netlink.rs"
2929

3030
[profile.release]
31+
debug = true
3132
lto = true
3233
panic = "abort" # Save size. We don't need unwinding anyway.
3334
# TODO is there any way to remove the ability to display backtraces? This would

src/ptools.rs

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,13 @@ fn get_flags(pid: u64, fd: u64) -> u64 {
497497
fn print_file(pid: u64, fd: u64, sockets: &HashMap<u64, SockInfo>) {
498498
let link_path_str = format!("/proc/{}/fd/{}", pid, fd);
499499
let link_path = Path::new(&link_path_str);
500-
let stat_info = stat(link_path).unwrap();
500+
let stat_info = match stat(link_path) {
501+
Err(e) => {
502+
eprintln!("failed to stat {}: {}", &link_path_str, e);
503+
return;
504+
},
505+
Ok(stat_info) => stat_info,
506+
};
501507

502508
let file_type = file_type(stat_info.st_mode, &link_path);
503509

@@ -541,8 +547,10 @@ fn print_file(pid: u64, fd: u64, sockets: &HashMap<u64, SockInfo>) {
541547
}
542548
},
543549
_ => {
544-
let path = fs::read_link(link_path).unwrap();
545-
print!(" {}\n", path.to_str().unwrap());
550+
match fs::read_link(link_path) {
551+
Ok(path) => println!(" {}", path.to_string_lossy()),
552+
Err(e) => eprintln!("failed to readlink {}: {}", &link_path_str, e),
553+
}
546554
}
547555
}
548556
}
@@ -794,28 +802,41 @@ fn fetch_sock_info(pid: u64) -> Result<HashMap<u64, SockInfo>, Box<dyn Error>> {
794802
* sockname: AF_INET6 :: port: 8341
795803
*/
796804

797-
fn print_files(pid: u64) {
805+
fn print_files(pid: u64) -> bool {
806+
807+
let proc_dir = format!("/proc/{}/", pid);
808+
if !Path::new(&proc_dir).exists() {
809+
eprintln!("No such directory {}", &proc_dir);
810+
return false;
811+
}
812+
798813
print_proc_summary(pid);
799814

800815
// TODO print current rlimit
801816

802-
// TODO BLOCKER handle permission errors by printing an error instead of just
803-
// not printing anything
804-
805817
let sockets = fetch_sock_info(pid).unwrap();
806818

807-
if let Ok(entries) = fs::read_dir(format!("/proc/{}/fd/", pid)) {
819+
let fd_dir = format!("/proc/{}/fd/", pid);
820+
let readdir_res = fs::read_dir(&fd_dir).and_then(|entries| {
808821
for entry in entries {
809-
let entry = entry.unwrap();
822+
let entry = entry?;
810823
let filename = entry.file_name();
811-
let filename = filename.to_str().unwrap();
812-
if let Ok(fd) = filename.parse::<u64>() {
824+
let filename = filename.to_string_lossy();
825+
if let Ok(fd) = (&filename).parse::<u64>() {
813826
print_file(pid, fd, &sockets);
814827
} else {
815-
eprint!("Unexpected file /proc/pid/fd/{} found", filename);
828+
eprint!("Unexpected file /proc/[pid]/fd/{} found", &filename);
816829
}
817-
}
830+
};
831+
Ok(())
832+
});
833+
834+
if let Err(e) = readdir_res {
835+
eprintln!("Unable to read {}: {}", &fd_dir, e);
836+
return false;
818837
}
838+
839+
return true;
819840
}
820841

821842
pub fn pargs_main() {
@@ -923,9 +944,14 @@ pub fn pfiles_main() {
923944
usage_err(program, opts);
924945
}
925946

947+
let mut error = false;
926948
for arg in &matches.free {
927949
let pid = arg.parse::<u64>().unwrap();
928-
print_files(pid);
950+
error = error || !print_files(pid);
951+
}
952+
953+
if error {
954+
exit(1);
929955
}
930956
}
931957

0 commit comments

Comments
 (0)