diff --git a/src/uu/ps/src/collector.rs b/src/uu/ps/src/collector.rs deleted file mode 100644 index e19e3fd..0000000 --- a/src/uu/ps/src/collector.rs +++ /dev/null @@ -1,107 +0,0 @@ -// This file is part of the uutils procps package. -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -use clap::ArgMatches; -#[cfg(target_family = "unix")] -use nix::errno::Errno; -use std::{cell::RefCell, rc::Rc}; -use uu_pgrep::process::{ProcessInformation, Teletype}; - -// TODO: Temporary add to this file, this function will add to uucore. -#[cfg(not(target_os = "redox"))] -#[cfg(target_family = "unix")] -fn getsid(pid: i32) -> Option { - unsafe { - let result = libc::getsid(pid); - if Errno::last() == Errno::UnknownErrno { - Some(result) - } else { - None - } - } -} - -// TODO: Temporary add to this file, this function will add to uucore. -#[cfg(target_family = "windows")] -fn getsid(_pid: i32) -> Option { - Some(0) -} - -// Default behavior: select processes with same terminal and same effective user ID -pub(crate) fn basic_collector( - proc_snapshot: &[Rc>], -) -> Vec>> { - let mut result = Vec::new(); - - let mut cur = ProcessInformation::current_process_info().unwrap(); - let tty = cur.tty(); - let euid = cur.euid().unwrap(); - - for proc_info in proc_snapshot { - if proc_info.borrow().tty() == tty && proc_info.borrow_mut().euid().unwrap() == euid { - result.push(proc_info.clone()); - } - } - - result -} - -/// Filter for processes -/// -/// - `-A` Select all processes. Identical to `-e`. -pub(crate) fn process_collector( - matches: &ArgMatches, - proc_snapshot: &[Rc>], -) -> Vec>> { - let mut result = Vec::new(); - - // flag `-A` - if matches.get_flag("A") { - result.extend(proc_snapshot.iter().map(Rc::clone)); - } - - result -} - -/// Filter for session -/// -/// - `-d` Select all processes except session leaders. -/// - `-a` Select all processes except both session leaders (see getsid(2)) and processes not associated with a terminal. -pub(crate) fn session_collector( - matches: &ArgMatches, - proc_snapshot: &[Rc>], -) -> Vec>> { - let mut result = Vec::new(); - - let tty = |proc: &Rc>| proc.borrow_mut().tty(); - - // flag `-d` - if matches.get_flag("d") { - for proc_info in proc_snapshot { - let pid = proc_info.borrow().pid; - - if getsid(pid as i32) != Some(pid as i32) { - result.push(proc_info.clone()); - } - } - } - - // flag `-a` - // Guessing it pid=sid, and associated terminal. - if matches.get_flag("a") { - for it in proc_snapshot { - let pid = it.borrow().pid; - - if let Some(sid) = getsid(pid as i32) { - // Check is session leader - if sid != (pid as i32) && tty(it) != Teletype::Unknown { - result.push(it.clone()); - } - } - } - } - - result -} diff --git a/src/uu/ps/src/process_selection.rs b/src/uu/ps/src/process_selection.rs new file mode 100644 index 0000000..5fb80ff --- /dev/null +++ b/src/uu/ps/src/process_selection.rs @@ -0,0 +1,87 @@ +// This file is part of the uutils procps package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use clap::ArgMatches; +use uu_pgrep::process::{walk_process, ProcessInformation, Teletype}; +use uucore::error::UResult; + +#[cfg(target_family = "unix")] +use nix::errno::Errno; + +// TODO: Temporary add to this file, this function will add to uucore. +#[cfg(not(target_os = "redox"))] +#[cfg(target_family = "unix")] +fn getsid(pid: i32) -> Option { + unsafe { + let result = libc::getsid(pid); + if Errno::last() == Errno::UnknownErrno { + Some(result) + } else { + None + } + } +} + +// TODO: Temporary add to this file, this function will add to uucore. +#[cfg(target_family = "windows")] +fn getsid(_pid: i32) -> Option { + Some(0) +} + +fn is_session_leader(process: &ProcessInformation) -> bool { + let pid = process.pid as i32; + getsid(pid) == Some(pid) +} + +pub struct ProcessSelectionSettings { + /// - `-A` Select all processes. Identical to `-e`. + pub select_all: bool, + /// - `-a` Select all processes except both session leaders (see getsid(2)) and processes not associated with a terminal. + pub select_non_session_leaders_with_tty: bool, + /// - `-d` Select all processes except session leaders. + pub select_non_session_leaders: bool, +} + +impl ProcessSelectionSettings { + pub fn from_matches(matches: &ArgMatches) -> Self { + Self { + select_all: matches.get_flag("A"), + select_non_session_leaders_with_tty: matches.get_flag("a"), + select_non_session_leaders: matches.get_flag("d"), + } + } + + pub fn select_processes(self) -> UResult> { + let mut current_process = ProcessInformation::current_process_info().unwrap(); + let current_tty = current_process.tty(); + let current_euid = current_process.euid().unwrap(); + + let matches_criteria = |process: &mut ProcessInformation| -> UResult { + if self.select_all { + return Ok(true); + } + + if self.select_non_session_leaders_with_tty { + return Ok(!is_session_leader(process) && process.tty() != Teletype::Unknown); + } + + if self.select_non_session_leaders { + return Ok(!is_session_leader(process)); + } + + // Default behavior: select processes with same terminal and same effective user ID + Ok(process.tty() == current_tty && process.euid().unwrap() == current_euid) + }; + + let mut selected = vec![]; + for mut process in walk_process() { + if matches_criteria(&mut process)? { + selected.push(process); + } + } + + Ok(selected) + } +} diff --git a/src/uu/ps/src/ps.rs b/src/uu/ps/src/ps.rs index f2df665..1159ef3 100644 --- a/src/uu/ps/src/ps.rs +++ b/src/uu/ps/src/ps.rs @@ -3,10 +3,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -mod collector; mod mapping; mod parser; mod picker; +mod process_selection; mod sorting; use clap::crate_version; @@ -19,8 +19,8 @@ use mapping::{ }; use parser::{parser, OptionalKeyValue}; use prettytable::{format::consts::FORMAT_CLEAN, Row, Table}; -use std::{cell::RefCell, rc::Rc}; -use uu_pgrep::process::walk_process; +use process_selection::ProcessSelectionSettings; +use std::cell::RefCell; use uucore::{ error::{UError, UResult, USimpleError}, format_usage, help_about, help_usage, @@ -33,20 +33,8 @@ const USAGE: &str = help_usage!("ps.md"); pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; - let snapshot = walk_process() - .map(|it| Rc::new(RefCell::new(it))) - .collect::>(); - let mut proc_infos = Vec::new(); - - if !matches.get_flag("A") && !matches.get_flag("a") && !matches.get_flag("d") { - proc_infos.extend(collector::basic_collector(&snapshot)); - } else { - proc_infos.extend(collector::process_collector(&matches, &snapshot)); - proc_infos.extend(collector::session_collector(&matches, &snapshot)); - } - - proc_infos.sort_by(|a, b| a.borrow().pid.cmp(&b.borrow().pid)); - proc_infos.dedup_by(|a, b| a.borrow().pid == b.borrow().pid); + let selection_settings = ProcessSelectionSettings::from_matches(&matches); + let mut proc_infos = selection_settings.select_processes()?; sorting::sort(&mut proc_infos, &matches); @@ -90,7 +78,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { for proc in proc_infos { let picked = pickers .iter() - .map(|picker| picker(Rc::unwrap_or_clone(proc.clone()))); + .map(|picker| picker(RefCell::new(proc.clone()))); rows.push(Row::from_iter(picked)); } diff --git a/src/uu/ps/src/sorting.rs b/src/uu/ps/src/sorting.rs index 77c4478..bed4946 100644 --- a/src/uu/ps/src/sorting.rs +++ b/src/uu/ps/src/sorting.rs @@ -4,15 +4,14 @@ // file that was distributed with this source code. use clap::ArgMatches; -use std::{cell::RefCell, rc::Rc}; use uu_pgrep::process::ProcessInformation; // TODO: Implementing sorting flags. -pub(crate) fn sort(input: &mut [Rc>], _matches: &ArgMatches) { +pub(crate) fn sort(input: &mut [ProcessInformation], _matches: &ArgMatches) { sort_by_pid(input); } /// Sort by pid. (Default) -fn sort_by_pid(input: &mut [Rc>]) { - input.sort_by(|a, b| a.borrow().pid.cmp(&b.borrow().pid)); +fn sort_by_pid(input: &mut [ProcessInformation]) { + input.sort_by(|a, b| a.pid.cmp(&b.pid)); }