From d5d1f5a6e83e123cbab80d36acbefc2e42f7ff1e Mon Sep 17 00:00:00 2001 From: llenotre Date: Tue, 2 Jul 2024 01:23:58 +0200 Subject: [PATCH] refactor: cleanup (wip) --- fdisk/src/guid.rs | 18 ++-- fdisk/src/main.rs | 6 +- fdisk/src/partition.rs | 86 ++++++++-------- login/src/main.rs | 2 +- mkfs/src/ext2.rs | 8 +- mkfs/src/main.rs | 4 +- ps/src/format.rs | 93 +++++------------ ps/src/main.rs | 173 ++++++++++++++------------------ ps/src/process/mod.rs | 27 ++--- ps/src/process/status_parser.rs | 42 +++----- ps/src/util.rs | 22 ---- su/src/main.rs | 14 ++- utils/src/user.rs | 4 +- 13 files changed, 190 insertions(+), 309 deletions(-) delete mode 100644 ps/src/util.rs diff --git a/fdisk/src/guid.rs b/fdisk/src/guid.rs index 6359184..7f99091 100644 --- a/fdisk/src/guid.rs +++ b/fdisk/src/guid.rs @@ -6,9 +6,9 @@ use std::str::FromStr; /// Type representing a Globally Unique IDentifier. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] #[repr(C, packed)] -pub struct GUID(pub [u8; 16]); +pub struct Guid(pub [u8; 16]); -impl FromStr for GUID { +impl FromStr for Guid { type Err = (); fn from_str(s: &str) -> Result { @@ -47,7 +47,7 @@ impl FromStr for GUID { } } -impl GUID { +impl Guid { /// Generates a random GUID. pub fn random() -> Self { let mut buf = [0; 16]; @@ -56,7 +56,7 @@ impl GUID { } } -impl fmt::Display for GUID { +impl fmt::Display for Guid { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { for i in (0..4).rev() { write!(fmt, "{:02x}", self.0[i])?; @@ -89,7 +89,7 @@ mod tests { #[test] pub fn guid_parse_valid() { - let guid = GUID::from_str("c12a7328-f81f-11d2-ba4b-00a0c93ec93b").unwrap(); + let guid = Guid::from_str("c12a7328-f81f-11d2-ba4b-00a0c93ec93b").unwrap(); assert_eq!( guid.0, [ @@ -98,7 +98,7 @@ mod tests { ] ); - let guid = GUID::from_str("C12A7328-F81F-11D2-BA4B-00A0C93EC93B").unwrap(); + let guid = Guid::from_str("C12A7328-F81F-11D2-BA4B-00A0C93EC93B").unwrap(); assert_eq!( guid.0, [ @@ -110,8 +110,8 @@ mod tests { #[test] pub fn guid_parse_invalid() { - GUID::from_str("c12a7328f81f11d2ba4b00a0c93ec93b").unwrap_err(); - GUID::from_str("c12a7328f81f11d2ba4b00a0c93ec93").unwrap_err(); - GUID::from_str("c12a7328f81f11d2ba4b00a0c93ec93$").unwrap_err(); + Guid::from_str("c12a7328f81f11d2ba4b00a0c93ec93b").unwrap_err(); + Guid::from_str("c12a7328f81f11d2ba4b00a0c93ec93").unwrap_err(); + Guid::from_str("c12a7328f81f11d2ba4b00a0c93ec93$").unwrap_err(); } } diff --git a/fdisk/src/main.rs b/fdisk/src/main.rs index 6fe59eb..d6b4b21 100644 --- a/fdisk/src/main.rs +++ b/fdisk/src/main.rs @@ -53,21 +53,17 @@ impl Args { fn parse_args() -> Args { let mut args: Args = Default::default(); - let mut iter = env::args(); args.prog = iter.next().unwrap_or("fdisk".to_owned()); args.script = args.prog.split('/').last() == Some("sfdisk"); - - while let Some(arg) = iter.next() { + for arg in iter { match arg.as_str() { "-h" | "--help" => args.help = true, "-l" | "--list" => args.list = true, - // TODO implement other options _ => args.disks.push(arg.into()), } } - args } diff --git a/fdisk/src/partition.rs b/fdisk/src/partition.rs index 4d8567f..a26f146 100644 --- a/fdisk/src/partition.rs +++ b/fdisk/src/partition.rs @@ -1,7 +1,7 @@ //! TODO use crate::crc32; -use crate::guid::GUID; +use crate::guid::Guid; use std::cmp::max; use std::cmp::min; use std::fmt; @@ -93,9 +93,9 @@ pub struct MBRTable { #[repr(C, packed)] struct GPTEntry { /// The partition type's GUID. - partition_type: GUID, + partition_type: Guid, /// The partition's GUID. - guid: GUID, + guid: Guid, /// The starting LBA. start: i64, /// The ending LBA. @@ -129,7 +129,7 @@ pub struct GPT { /// The last usable sector. last_usable: i64, /// The disk's GUID. - disk_guid: GUID, + disk_guid: Guid, /// The LBA of the beginning of the GUID partition entries array. entries_start: i64, /// The number of entries in the table. @@ -144,16 +144,16 @@ pub struct GPT { #[derive(Debug, Eq, PartialEq)] pub enum PartitionTableType { /// Master Boot Record. - MBR, + Mbr, /// Globally Unique Identifier Partition Table. - GPT, + Gpt, } impl PartitionTableType { /// Prints known partition types. pub fn print_partition_types(&self) { match self { - Self::MBR => { + Self::Mbr => { let types = &[ (0x00, "Empty"), (0x01, "FAT12"), @@ -270,7 +270,7 @@ impl PartitionTableType { } } - Self::GPT => { + Self::Gpt => { let types = &[ ("EFI System", "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"), ( @@ -809,10 +809,10 @@ impl PartitionTableType { } // TODO Return result instead - /// Prompts for informations related to a new partition to be created. + /// Prompts for information related to a new partition to be created. pub fn prompt_new_partition(&self) -> Partition { let (_extended, max_partition_count) = match self { - Self::MBR => { + Self::Mbr => { // TODO get info from disk, to be passed as argument println!("Partition type"); println!(" p primary (TODO primary, TODO extended, TODO free)"); // TODO @@ -824,7 +824,7 @@ impl PartitionTableType { (extended, 4) } - Self::GPT => (false, 128), + Self::Gpt => (false, 128), }; // Ask partition number @@ -869,8 +869,8 @@ impl PartitionTableType { // TODO use other values? let part_type = match self { - Self::MBR => PartitionType::MBR(0), - Self::GPT => PartitionType::GPT(GUID([0; 16])), + Self::Mbr => PartitionType::Mbr(0), + Self::Gpt => PartitionType::Gpt(Guid([0; 16])), }; Partition { @@ -888,7 +888,7 @@ impl PartitionTableType { /// Reads partitions from the storage device represented by `dev` and returns the list. pub fn read(&self, dev: &mut File, sectors_count: u64) -> io::Result>> { match self { - Self::MBR => { + Self::Mbr => { let mut buff: [u8; size_of::()] = [0; size_of::()]; dev.seek(SeekFrom::Start(0))?; dev.read_exact(&mut buff)?; @@ -906,7 +906,7 @@ impl PartitionTableType { start: p.lba_start as _, size: p.sectors_count as _, - part_type: PartitionType::MBR(p.partition_type), + part_type: PartitionType::Mbr(p.partition_type), uuid: None, @@ -916,7 +916,7 @@ impl PartitionTableType { Ok(Some(parts)) } - Self::GPT => { + Self::Gpt => { let mut buff: [u8; size_of::()] = [0; size_of::()]; dev.seek(SeekFrom::Start(512))?; dev.read_exact(&mut buff)?; @@ -967,7 +967,7 @@ impl PartitionTableType { start: entry.start as _, size: (entry.end - entry.start) as _, - part_type: PartitionType::GPT(entry.partition_type), + part_type: PartitionType::Gpt(entry.partition_type), uuid: Some(entry.guid), @@ -1024,7 +1024,7 @@ impl PartitionTableType { sectors_count: u64, ) -> io::Result<()> { match self { - Self::MBR => { + Self::Mbr => { let mut mbr = MBRTable { boot: [0; 440], disk_signature: 0, @@ -1039,7 +1039,7 @@ impl PartitionTableType { } for (i, p) in partitions.iter().enumerate() { - let PartitionType::MBR(partition_type) = p.part_type else { + let PartitionType::Mbr(partition_type) = p.part_type else { panic!("invalid partition type of MBR table"); }; mbr.partitions[i] = MBRPartition { @@ -1062,20 +1062,20 @@ impl PartitionTableType { dev.write_all(slice) } - Self::GPT => { + Self::Gpt => { if partitions.len() > 128 { // TODO error todo!(); } // Write protective MBR - Self::MBR.write( + Self::Mbr.write( dev, &[Partition { start: 1, size: min(u32::MAX as u64, sectors_count - 1), - part_type: PartitionType::MBR(0xee), + part_type: PartitionType::Mbr(0xee), uuid: None, @@ -1095,7 +1095,7 @@ impl PartitionTableType { alternate_hdr_lba: -1, first_usable: 34, last_usable: -34, - disk_guid: GUID::random(), + disk_guid: Guid::random(), entries_start: 2, entries_number: partitions.len() as _, entry_size: 128, @@ -1106,7 +1106,7 @@ impl PartitionTableType { let parts: Vec = partitions .iter() .map(|p| { - let PartitionType::GPT(partition_type) = p.part_type else { + let PartitionType::Gpt(partition_type) = p.part_type else { panic!("invalid partition type of GPT table"); }; GPTEntry { @@ -1157,8 +1157,8 @@ impl PartitionTableType { impl fmt::Display for PartitionTableType { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::MBR => write!(fmt, "dos"), - Self::GPT => write!(fmt, "gpt"), + Self::Mbr => write!(fmt, "dos"), + Self::Gpt => write!(fmt, "gpt"), } } } @@ -1167,14 +1167,14 @@ impl fmt::Display for PartitionTableType { #[derive(Clone, Debug, Eq, PartialEq)] pub enum PartitionType { /// MBR partition type. - MBR(u8), + Mbr(u8), /// GPT partition type. - GPT(GUID), + Gpt(Guid), } impl Default for PartitionType { fn default() -> Self { - Self::MBR(0) + Self::Mbr(0) } } @@ -1182,9 +1182,9 @@ impl FromStr for PartitionType { type Err = (); fn from_str(s: &str) -> Result { - GUID::from_str(s) - .map(Self::GPT) - .or_else(|_| u8::from_str_radix(s, 16).map(Self::MBR)) + Guid::from_str(s) + .map(Self::Gpt) + .or_else(|_| u8::from_str_radix(s, 16).map(Self::Mbr)) .map_err(|_| ()) } } @@ -1192,8 +1192,8 @@ impl FromStr for PartitionType { impl Display for PartitionType { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::MBR(n) => write!(fmt, "{n:x}"), - Self::GPT(n) => write!(fmt, "{n}"), + Self::Mbr(n) => write!(fmt, "{n:x}"), + Self::Gpt(n) => write!(fmt, "{n}"), } } } @@ -1210,7 +1210,7 @@ pub struct Partition { pub part_type: PartitionType, /// The partition's UUID. - pub uuid: Option, + pub uuid: Option, /// Tells whether the partition is bootable. pub bootable: bool, @@ -1253,7 +1253,7 @@ impl PartitionTable { /// /// If the table is invalid, the function returns an empty MBR table. pub fn read(dev: &mut File, sectors_count: u64) -> io::Result { - for t in [PartitionTableType::GPT, PartitionTableType::MBR] { + for t in [PartitionTableType::Gpt, PartitionTableType::Mbr] { if let Some(partitions) = t.read(dev, sectors_count)? { return Ok(PartitionTable { table_type: t, @@ -1262,7 +1262,7 @@ impl PartitionTable { } } Ok(PartitionTable { - table_type: PartitionTableType::MBR, + table_type: PartitionTableType::Mbr, partitions: vec![], }) } @@ -1368,7 +1368,7 @@ impl FromStr for PartitionTable { let Some(val) = value else { return Err("`uuid` requires a value".into()); }; - let Ok(val) = GUID::from_str(val) else { + let Ok(val) = Guid::from_str(val) else { return Err(format!("Invalid value for `uuid`: {val}")); }; part.uuid = Some(val); @@ -1383,7 +1383,7 @@ impl FromStr for PartitionTable { }) .collect::, _>>()?; Ok(Self { - table_type: PartitionTableType::MBR, // TODO + table_type: PartitionTableType::Mbr, // TODO partitions, }) } @@ -1396,7 +1396,7 @@ mod test { #[test] fn partitions_serialize0() { let table0 = PartitionTable { - table_type: PartitionTableType::MBR, + table_type: PartitionTableType::Mbr, partitions: vec![], }; @@ -1409,14 +1409,14 @@ mod test { #[test] fn partitions_serialize1() { let table0 = PartitionTable { - table_type: PartitionTableType::MBR, + table_type: PartitionTableType::Mbr, partitions: vec![Partition { start: 0, size: 1, - part_type: PartitionType::MBR(0xab), + part_type: PartitionType::Mbr(0xab), - uuid: Some(GUID([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])), + uuid: Some(Guid([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])), bootable: false, }], diff --git a/login/src/main.rs b/login/src/main.rs index 2d03776..a2bacd4 100644 --- a/login/src/main.rs +++ b/login/src/main.rs @@ -20,7 +20,7 @@ use utils::util::get_hostname; fn build_env_var(name: &str, value: impl IntoIterator) -> CString { let data: Vec = name .as_bytes() - .into_iter() + .iter() .cloned() .chain(iter::once(b'=')) .chain(value) diff --git a/mkfs/src/ext2.rs b/mkfs/src/ext2.rs index 57e4548..5a9478e 100644 --- a/mkfs/src/ext2.rs +++ b/mkfs/src/ext2.rs @@ -213,8 +213,8 @@ impl BlockGroupDescriptor { /// /// `superblock` is the filesystem's superblock. pub fn get_disk_offset(i: u32, superblock: &Superblock) -> u64 { - let bgdt_off = (SUPERBLOCK_OFFSET / superblock.get_block_size() as u64) + 1; - (bgdt_off * superblock.get_block_size() as u64) + (i as u64 * size_of::() as u64) + let bgdt_off = (SUPERBLOCK_OFFSET / superblock.get_block_size()) + 1; + (bgdt_off * superblock.get_block_size()) + (i as u64 * size_of::() as u64) } /// Reads and returns the `i`th block group descriptor. @@ -303,7 +303,7 @@ impl INode { fn get_disk_offset(i: NonZeroU32, superblock: &Superblock, dev: &mut File) -> io::Result { let i = i.get(); - let blk_size = superblock.get_block_size() as u64; + let blk_size = superblock.get_block_size(); let inode_size = superblock.get_inode_size() as u64; // The block group the inode is located in @@ -590,7 +590,7 @@ impl FSFactory for Ext2Factory { // Create `.` and `..` entries for the root directory let entries_block = used_blocks_end - 1; - let entries_block_off = entries_block as u64 * block_size as u64; + let entries_block_off = entries_block as u64 * block_size; root_dir.i_block[0] = entries_block; dev.seek(SeekFrom::Start(entries_block_off))?; let self_entry = DirectoryEntry { diff --git a/mkfs/src/main.rs b/mkfs/src/main.rs index 366bb36..d5de670 100644 --- a/mkfs/src/main.rs +++ b/mkfs/src/main.rs @@ -41,10 +41,9 @@ fn parse_args() -> Args { }; args.fs_type = fs_type.unwrap_or("ext2").to_owned(); - while let Some(arg) = iter.next() { + for arg in iter { match arg.as_str() { "-h" | "--help" => args.help = true, - // TODO implement other options // TODO get device path _ => { @@ -53,7 +52,6 @@ fn parse_args() -> Args { } } } - args } diff --git a/ps/src/format.rs b/ps/src/format.rs index ba22ea9..e7f1833 100644 --- a/ps/src/format.rs +++ b/ps/src/format.rs @@ -55,7 +55,6 @@ impl Name { "tty" => Some(Self::Tty), "comm" => Some(Self::Comm), "args" => Some(Self::Args), - _ => None, } } @@ -81,101 +80,63 @@ impl Name { } } -/// Structure representing a display format. -pub struct DisplayFormat { - /// The list of names to be displayed along with their respective display name. - pub names: Vec<(Name, String)>, -} +/// A display format. +pub struct DisplayFormat(pub Vec<(Name, String)>); impl DisplayFormat { - /// Creates a new empty instance. - pub fn new() -> Self { - Self { names: Vec::new() } - } - /// Tells whether the display format can be printed. pub fn can_print(&self) -> bool { - self.names + self.0 .iter() .any(|(_, display_name)| !display_name.is_empty()) } - - /// Concats the given format to the current. - pub fn concat(&mut self, mut other: Self) { - self.names.append(&mut other.names); - } } impl Default for DisplayFormat { fn default() -> Self { - Self { - names: vec![ - (Name::Pid, Name::Pid.get_default_display().to_owned()), - (Name::Tty, Name::Tty.get_default_display().to_owned()), - // TODO (Name::Time, Name::Time.get_default_display().to_owned()), - (Name::Comm, Name::Comm.get_default_display().to_owned()), - ], - } + Self(vec![ + (Name::Pid, Name::Pid.get_default_display().to_owned()), + (Name::Tty, Name::Tty.get_default_display().to_owned()), + // TODO (Name::Time, Name::Time.get_default_display().to_owned()), + (Name::Comm, Name::Comm.get_default_display().to_owned()), + ]) } } impl fmt::Display for DisplayFormat { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - for (name, disp) in &self.names { + for (name, disp) in &self.0 { if !disp.is_empty() { - write!(fmt, " {}", disp)?; + write!(fmt, " {disp}")?; } else { // Add padding the same size as the default display name - let len = name.get_default_display().len() + 1; - for _ in 0..len { - write!(fmt, " ")?; - } + write!(fmt, "{: { - /// The format to be parsed. - format: &'a str, -} - -impl<'a> FormatParser<'a> { - /// Creates a new instance for the given format. - pub fn new(format: &'a str) -> Self { - Self { format } - } - - /// Parses the format and returns the corresponding structure. - pub fn yield_format(self) -> Result { - let mut names = vec![]; - - let s = self - .format - .split(|ch: char| ch == ',' || ch.is_ascii_whitespace()); - for n in s { - // Splitting name and display name - let split = n.find('=').map(|i| { - let (name, display_name) = n.split_at(i); - (name, display_name[1..].to_owned()) +/// Parses the given display format. +pub fn parse_display_format(s: &str) -> Result { + let names = s + .split(|c: char| c == ',' || c.is_ascii_whitespace()) + .map(|s| { + // Split name and display name + let split = s.find('=').map(|i| { + let (name, display_name) = s.split_at(i); + (name, &display_name[1..]) }); - if let Some((name, display_name)) = split { let name = Name::from_str(name).ok_or(())?; - - names.push((name, display_name)); + Ok((name, display_name.to_owned())) } else { - let name = Name::from_str(n).ok_or(())?; + let name = Name::from_str(s).ok_or(())?; let display_name = name.get_default_display(); - - names.push((name, display_name.to_owned())); + Ok((name, display_name.to_owned())) } - } - - Ok(DisplayFormat { names }) - } + }) + .collect::>()?; + Ok(DisplayFormat(names)) } diff --git a/ps/src/main.rs b/ps/src/main.rs index f707ad2..ecca0e0 100644 --- a/ps/src/main.rs +++ b/ps/src/main.rs @@ -1,11 +1,12 @@ //! The `ps` command allows to print the list of processes running on the system. +#![feature(option_get_or_insert_default)] + mod format; mod process; -mod util; +use crate::format::parse_display_format; use format::DisplayFormat; -use format::FormatParser; use process::Process; use process::ProcessIterator; use std::process::exit; @@ -85,11 +86,6 @@ fn error(msg: &str) -> ! { // TODO When a PID, UID, GID... is specified, use files' metadata to avoid reading /// Parses arguments and returns the selectors list and format. fn parse_args() -> io::Result<(Vec, DisplayFormat)> { - // Results - let mut selectors = Vec::new(); - let mut format = DisplayFormat::new(); - let mut default_format = true; - // Read users and groups lists let users_buff = fs::read_to_string(PASSWD_PATH)?; let users: Vec<_> = User::deserialize(&users_buff) @@ -99,7 +95,9 @@ fn parse_args() -> io::Result<(Vec, DisplayFormat)> { let groups: Vec<_> = Group::deserialize(&groups_buff) .filter_map(Result::ok) .collect(); - + // Results + let mut selectors = Vec::new(); + let mut format: Option = None; // TODO -l and -f let mut args = env::args().skip(1); while let Some(arg) = args.next() { @@ -107,139 +105,116 @@ fn parse_args() -> io::Result<(Vec, DisplayFormat)> { "-a" => selectors.push(Selector::Terminal), "-A" | "-e" => selectors.push(Selector::All), "-d" => selectors.push(Selector::NoLeaders), - "-o" => { - if let Some(format_str) = args.next() { - let parser = FormatParser::new(&format_str); - - match parser.yield_format() { - Ok(f) => { - format.concat(f); - default_format = false; - } - - Err(_) => error("invalid format"), - } - } else { + let Some(str) = args.next() else { error("format specification must follow -o"); - } + }; + let Ok(mut f) = parse_display_format(&str) else { + error("invalid format"); + }; + let format = format.get_or_insert_default(); + format.0.append(&mut f.0); } - "-p" => { - if let Some(pids_str) = args.next() { - let iter = match util::parse_nbr_list(&pids_str) { - Ok(list) => list.into_iter(), - - Err(_) => error("process ID list syntax error"), - }; - - let mut pids = iter.map(Selector::Pid).collect(); - selectors.append(&mut pids); - } else { + let Some(pids_str) = args.next() else { error("list of process IDs must follow -p"); - } + }; + let pids: Result, _> = pids_str + .split(|c: char| c.is_ascii_whitespace()) + .map(|s| s.parse().map(Selector::Pid)) + .collect(); + let Ok(mut pids) = pids else { + error("process ID list syntax error"); + }; + selectors.append(&mut pids); } - "-t" => { if let Some(termlist) = args.next() { - let mut terms = util::parse_str_list(&termlist) - .into_iter() - .map(Selector::Term) - .collect(); - - selectors.append(&mut terms); - } else { + let terms = termlist + .split(|c: char| c.is_ascii_whitespace()) + .map(String::from) + .map(Selector::Term); + selectors.extend(terms); } } - "-u" => { if let Some(users_list) = args.next() { - util::parse_str_list(&users_list) - .into_iter() - .for_each(|user| match users.iter().find(|u| u.login_name == user) { - Some(user) => selectors.push(Selector::Uid(user.uid)), - - None => match user.parse::() { - Ok(uid) => selectors.push(Selector::Uid(uid)), - Err(_) => {} - }, + users_list + .split(|c: char| c.is_ascii_whitespace()) + .for_each(|login| { + let user = users.iter().find(|u| u.login_name == login); + match user { + Some(user) => selectors.push(Selector::Uid(user.uid)), + None => { + if let Ok(uid) = login.parse::() { + selectors.push(Selector::Uid(uid)); + } + } + } }); } else { selectors.push(Selector::Uid(get_euid())); } } - "-U" => { - if let Some(users_list) = args.next() { - util::parse_str_list(&users_list) - .into_iter() - .for_each(|user| match users.iter().find(|u| u.login_name == user) { - Some(user) => selectors.push(Selector::Ruid(user.uid)), - - None => match user.parse::() { - Ok(uid) => selectors.push(Selector::Ruid(uid)), - Err(_) => {} - }, - }); - } else { + let Some(users_list) = args.next() else { error("list of real users must follow -U"); - } + }; + users_list + .split(|c: char| c.is_ascii_whitespace()) + .for_each(|user| match users.iter().find(|u| u.login_name == user) { + Some(user) => selectors.push(Selector::Ruid(user.uid)), + None => { + if let Ok(uid) = user.parse::() { + selectors.push(Selector::Ruid(uid)); + } + } + }); } - "-g" => { if let Some(groups_list) = args.next() { - util::parse_str_list(&groups_list) - .into_iter() + groups_list + .split(|c: char| c.is_ascii_whitespace()) .for_each( |group| match groups.iter().find(|g| g.group_name == group) { Some(group) => selectors.push(Selector::Gid(group.gid)), - - None => match group.parse::() { - Ok(gid) => selectors.push(Selector::Gid(gid)), - Err(_) => {} - }, + None => { + if let Ok(gid) = group.parse::() { + selectors.push(Selector::Gid(gid)); + } + } }, ); } else { selectors.push(Selector::Gid(get_egid())); } } - "-G" => { - if let Some(groups_list) = args.next() { - util::parse_str_list(&groups_list) - .into_iter() - .for_each( - |group| match groups.iter().find(|g| g.group_name == group) { - Some(group) => selectors.push(Selector::Rgid(group.gid)), - - None => match group.parse::() { - Ok(gid) => selectors.push(Selector::Rgid(gid)), - Err(_) => {} - }, - }, - ); - } else { + let Some(groups_list) = args.next() else { error("list of real groups must follow -G"); - } + }; + groups_list + .split(|c: char| c.is_ascii_whitespace()) + .for_each( + |group| match groups.iter().find(|g| g.group_name == group) { + Some(group) => selectors.push(Selector::Rgid(group.gid)), + None => { + if let Ok(gid) = group.parse::() { + selectors.push(Selector::Rgid(gid)); + } + } + }, + ); } - _ => error("error: garbage option"), } } - // If no selector is specified, use defaults if selectors.is_empty() { // TODO Select only processes that share the same controlling terminal selectors.push(Selector::Uid(get_euid())); } - - // If no format is specified, use default - if default_format { - format = DisplayFormat::default(); - } - - Ok((selectors, format)) + Ok((selectors, format.unwrap_or_default())) } fn main() { diff --git a/ps/src/process/mod.rs b/ps/src/process/mod.rs index c58c7a0..af033ae 100644 --- a/ps/src/process/mod.rs +++ b/ps/src/process/mod.rs @@ -1,4 +1,4 @@ -//! Module implementing process structures. +//! Process structures. mod status_parser; @@ -10,7 +10,7 @@ use std::fs; use std::fs::ReadDir; use std::io; -/// Structure representing a process. +/// A process. #[derive(Debug, Default)] pub struct Process { /// The process's name. @@ -37,13 +37,13 @@ pub struct Process { } impl Process { - /// Returns an instance of ProcessDisplay, used to display a process with the given format. + /// Returns an instance of [`ProcessDisplay`], used to display a process with the given `format`. pub fn display<'p, 'f>(&'p self, format: &'f DisplayFormat) -> ProcessDisplay<'p, 'f> { ProcessDisplay { proc: self, format } } } -/// Structure used to display a process's informations. +/// Display of a process's information. pub struct ProcessDisplay<'p, 'f> { /// The process. proc: &'p Process, @@ -53,7 +53,7 @@ pub struct ProcessDisplay<'p, 'f> { impl<'f, 'p> fmt::Display for ProcessDisplay<'f, 'p> { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - for (name, _) in &self.format.names { + for (name, _) in &self.format.0 { match name { Name::Ruser => write!(fmt, " {}", self.proc.ruid)?, Name::User => write!(fmt, " {}", self.proc.uid)?, @@ -68,38 +68,31 @@ impl<'f, 'p> fmt::Display for ProcessDisplay<'f, 'p> { // TODO Name::Etime => todo!(), // TODO Name::Time => todo!(), Name::Tty => match &self.proc.tty { - Some(tty) => write!(fmt, " {}", tty)?, + Some(tty) => write!(fmt, " {tty}")?, None => write!(fmt, " ?")?, }, - Name::Comm => write!(fmt, " {}", self.proc.name)?, Name::Args => write!(fmt, " {}", self.proc.full_cmd)?, } } - Ok(()) } } /// An iterator on the system's processes. -pub struct ProcessIterator { - /// The iterator on procfs files. - files: ReadDir, -} +pub struct ProcessIterator(ReadDir); impl ProcessIterator { /// Creates a new instance. - pub fn new() -> Result { - Ok(Self { - files: fs::read_dir("/proc")?, - }) + pub fn new() -> io::Result { + Ok(Self(fs::read_dir("/proc")?)) } /// Returns the next PID in the iterator. /// If no PID is left, the function returns None. /// On error, the caller must retry. fn next_pid(&mut self) -> Option> { - let entry = match self.files.next()? { + let entry = match self.0.next()? { Ok(e) => e, Err(_) => return Some(Err(())), }; diff --git a/ps/src/process/status_parser.rs b/ps/src/process/status_parser.rs index c005f32..9b1cca8 100644 --- a/ps/src/process/status_parser.rs +++ b/ps/src/process/status_parser.rs @@ -1,74 +1,57 @@ -//! This module implements a parser for the status of a process. +//! Process status parsing. use super::Process; use std::fs; use std::io; -/// The status parser parses the content of the file `/proc/{pid}/status`, where `{pid}` is the pid -/// of the process. +/// Parses the content of the file `/proc/{pid}/status`, where `{pid}` is the pid of the process. pub struct StatusParser { /// The status file's content. - status_content: String, + status: String, /// The cmdline file's content. - cmdline_content: String, + cmdline: String, } impl StatusParser { /// Creates a new instance for the given pid `pid`. - pub fn new(pid: u32) -> Result { - // Reading the process's status file - let status_content = fs::read_to_string(format!("/proc/{}/status", pid))?; - - // Reading the process's status file - let cmdline_content = fs::read_to_string(format!("/proc/{}/cmdline", pid))?; - - Ok(Self { - status_content, - cmdline_content, - }) + pub fn new(pid: u32) -> io::Result { + let status = fs::read_to_string(format!("/proc/{pid}/status"))?; + let cmdline = fs::read_to_string(format!("/proc/{pid}/cmdline"))?; + Ok(Self { status, cmdline }) } /// Creates a process structure from files. pub fn yield_process(self) -> Result { let mut proc = Process::default(); - - for line in self.status_content.split('\n') { + for line in self.status.split('\n') { if line.is_empty() { continue; } - - // Splitting the line to get the name and value + // Split the line to get the name and value let (name, value) = line.find(':').map(|i| line.split_at(i)).ok_or(())?; let name = name.to_lowercase(); let value = value[1..].trim(); - match name.as_str() { "name" => proc.name = value.to_string(), - "pid" => proc.pid = value.parse::().map_err(|_| ())?, "ppid" => proc.ppid = value.parse::().map_err(|_| ())?, - "uid" => { let mut s = value.split_whitespace(); - proc.uid = s.nth(0).ok_or(())?.parse::().map_err(|_| ())?; proc.ruid = s.nth(2).ok_or(())?.parse::().map_err(|_| ())?; } "gid" => { let mut s = value.split_whitespace(); - proc.gid = s.nth(0).ok_or(())?.parse::().map_err(|_| ())?; proc.rgid = s.nth(2).ok_or(())?.parse::().map_err(|_| ())?; } - // TODO tty _ => {} } } - - // Getting full command line + // Get full command line let mut cmdline = self - .cmdline_content + .cmdline .chars() .map(|c| match c { '\0' => ' ', @@ -77,7 +60,6 @@ impl StatusParser { .collect::(); cmdline.pop(); proc.full_cmd = cmdline; - Ok(proc) } } diff --git a/ps/src/util.rs b/ps/src/util.rs deleted file mode 100644 index db413a9..0000000 --- a/ps/src/util.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Module implementing utility functions. - -/// Parses a list of strings from the given string. -/// On syntax error, the function returns an error. -pub fn parse_str_list(s: &str) -> Vec { - s.split(|c: char| c == ' ' || c == '\t' || c == ',') - .map(|s| s.to_string()) - .collect() -} - -/// Parses a list of numbers from the given string. -/// On syntax error, the function returns an error. -pub fn parse_nbr_list(s: &str) -> Result, ()> { - let iter = s.split(|c: char| c == ' ' || c == '\t' || c == ','); - let mut list = Vec::new(); - - for e in iter { - list.push(e.parse::().map_err(|_| ())?); - } - - Ok(list) -} diff --git a/su/src/main.rs b/su/src/main.rs index 216268d..50966da 100644 --- a/su/src/main.rs +++ b/su/src/main.rs @@ -43,18 +43,16 @@ fn parse_args(args: &Vec) -> Args<'_> { // Parsing options if present if has_options { - while let Some(a) = iter.next() { - if a == "-" { + for arg in iter.by_ref() { + if arg == "-" { break; } - // TODO } } - result.user = iter.next().map(|s| s.as_str()); - result.args = iter.map(|s| s.as_str()).collect(); - + result.user = iter.next().map(String::as_str); + result.args = iter.map(String::as_str).collect(); result } @@ -73,12 +71,12 @@ fn main() { // TODO Change user // Running the shell - let status = Command::new(&shell) + let status = Command::new(shell) .args(args.args) // TODO Set env .status() .unwrap_or_else(|_| { - eprintln!("su: Failed to run shell `{}`", shell); + eprintln!("su: Failed to run shell `{shell}`"); exit(1); }); diff --git a/utils/src/user.rs b/utils/src/user.rs index 67c2f56..35c7afe 100644 --- a/utils/src/user.rs +++ b/utils/src/user.rs @@ -102,7 +102,7 @@ impl User<'_> { if self.password.is_empty() || self.password == "x" { return None; } - Some(check_password(&self.password, pass)) + Some(check_password(self.password, pass)) } } @@ -175,7 +175,7 @@ impl Shadow<'_> { /// Check the given (not hashed) password `pass` against `self`. pub fn check_password(&self, pass: &str) -> bool { - check_password(&self.password, pass) + check_password(self.password, pass) } }