From 7ab76357777bac242644d649d612255e91947c21 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 9 Oct 2024 15:26:08 +0200 Subject: [PATCH] pmap: use Perms struct instead of String for perms --- src/uu/pmap/src/maps_format_parser.rs | 85 ++++++++++++++++++--------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/src/uu/pmap/src/maps_format_parser.rs b/src/uu/pmap/src/maps_format_parser.rs index d3ec057..8d9ced8 100644 --- a/src/uu/pmap/src/maps_format_parser.rs +++ b/src/uu/pmap/src/maps_format_parser.rs @@ -3,18 +3,58 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +use std::fmt; + // Represents a parsed single line from /proc//maps for the default and device formats. It // omits the inode information because it's not used by those formats. #[derive(Debug, PartialEq)] pub struct MapLine { pub address: String, pub size_in_kb: u64, - pub perms: String, + pub perms: Perms, pub offset: String, pub device: String, pub mapping: String, } +// Represents a set of permissions from the "perms" column of /proc//maps. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Perms { + pub readable: bool, + pub writable: bool, + pub executable: bool, + pub shared: bool, +} + +impl From<&str> for Perms { + fn from(s: &str) -> Self { + let mut chars = s.chars(); + + Self { + readable: chars.next() == Some('r'), + writable: chars.next() == Some('w'), + executable: chars.next() == Some('x'), + shared: chars.next() == Some('s'), + } + } +} + +// Please note: While `Perms` has four boolean fields, it's string representation has five +// characters because pmap's default and device formats use five characters for the perms, +// with the last character always being '-'. +impl fmt::Display for Perms { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}{}{}{}-", + if self.readable { 'r' } else { '-' }, + if self.writable { 'w' } else { '-' }, + if self.executable { 'x' } else { '-' }, + if self.shared { 's' } else { '-' }, + ) + } +} + // Parses a single line from /proc//maps. It assumes the format of `line` is correct (see // https://www.kernel.org/doc/html/latest/filesystems/proc.html for details). pub fn parse_map_line(line: &str) -> MapLine { @@ -22,7 +62,7 @@ pub fn parse_map_line(line: &str) -> MapLine { let (address, size_in_kb) = parse_address(memory_range); let (perms, rest) = rest.split_once(' ').expect("line should contain 2nd ' '"); - let perms = parse_perms(perms); + let perms = Perms::from(perms); let (offset, rest) = rest.split_once(' ').expect("line should contain 3rd ' '"); let offset = format!("{offset:0>16}"); @@ -59,15 +99,6 @@ fn parse_address(memory_range: &str) -> (String, u64) { (format!("{start:0>16}"), size_in_kb) } -// Turns a 4-char perms string from /proc//maps into a 5-char perms string. The first three -// chars are left untouched. -fn parse_perms(perms: &str) -> String { - let perms = perms.replace("p", "-"); - - // the fifth char seems to be always '-' in the original pmap - format!("{perms}-") -} - // Pads the device info from /proc//maps with zeros and turns AB:CD into 0AB:000CD. fn parse_device(device: &str) -> String { if let Some((major, minor)) = device.split_once(':') { @@ -99,7 +130,7 @@ mod test { fn create_map_line( address: &str, size_in_kb: u64, - perms: &str, + perms: Perms, offset: &str, device: &str, mapping: &str, @@ -107,42 +138,49 @@ mod test { MapLine { address: address.to_string(), size_in_kb, - perms: perms.to_string(), + perms, offset: offset.to_string(), device: device.to_string(), mapping: mapping.to_string(), } } + #[test] + fn test_perms_to_string() { + assert_eq!("-----", Perms::from("---p").to_string()); + assert_eq!("---s-", Perms::from("---s").to_string()); + assert_eq!("rwx--", Perms::from("rwxp").to_string()); + } + #[test] fn test_parse_map_line() { let data = [ ( - create_map_line("000062442eb9e000", 16, "r----", "0000000000000000", "008:00008", "konsole"), + create_map_line("000062442eb9e000", 16, Perms::from("r--p"), "0000000000000000", "008:00008", "konsole"), "62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole" ), ( - create_map_line("000071af50000000", 132, "rw---", "0000000000000000", "000:00000", " [ anon ]"), + create_map_line("000071af50000000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", " [ anon ]"), "71af50000000-71af50021000 rw-p 00000000 00:00 0 " ), ( - create_map_line("00007ffc3f8df000", 132, "rw---", "0000000000000000", "000:00000", " [ stack ]"), + create_map_line("00007ffc3f8df000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", " [ stack ]"), "7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]" ), ( - create_map_line("000071af8c9e6000", 16, "rw-s-", "0000000105830000", "000:00010", " [ anon ]"), + create_map_line("000071af8c9e6000", 16, Perms::from("rw-s"), "0000000105830000", "000:00010", " [ anon ]"), "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem" ), ( - create_map_line("000071af6cf0c000", 3560, "rw-s-", "0000000000000000", "000:00001", "memfd:wayland-shm (deleted)"), + create_map_line("000071af6cf0c000", 3560, Perms::from("rw-s"), "0000000000000000", "000:00001", "memfd:wayland-shm (deleted)"), "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)" ), ( - create_map_line("ffffffffff600000", 4, "--x--", "0000000000000000", "000:00000", " [ anon ]"), + create_map_line("ffffffffff600000", 4, Perms::from("--xp"), "0000000000000000", "000:00000", " [ anon ]"), "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]" ), ( - create_map_line("00005e8187da8000", 24, "r----", "0000000000000000", "008:00008", "hello world"), + create_map_line("00005e8187da8000", 24, Perms::from("r--p"), "0000000000000000", "008:00008", "hello world"), "5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world" ), ]; @@ -163,13 +201,6 @@ mod test { assert_eq!(size, 132); } - #[test] - fn test_parse_perms() { - assert_eq!("-----", parse_perms("---p")); - assert_eq!("---s-", parse_perms("---s")); - assert_eq!("rwx--", parse_perms("rwxp")); - } - #[test] fn test_parse_device() { assert_eq!("012:00034", parse_device("12:34"));