mirror of
https://github.com/uutils/procps.git
synced 2026-05-06 06:06:43 -04:00
ps: Refactor process selection
Refactor the process selection to better support cases where the behaviour is more complex than simply union of what each individual flag would list. This is bit similar to what is used in pgrep.
This commit is contained in:
@@ -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<i32> {
|
||||
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<i32> {
|
||||
Some(0)
|
||||
}
|
||||
|
||||
// Default behavior: select processes with same terminal and same effective user ID
|
||||
pub(crate) fn basic_collector(
|
||||
proc_snapshot: &[Rc<RefCell<ProcessInformation>>],
|
||||
) -> Vec<Rc<RefCell<ProcessInformation>>> {
|
||||
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<RefCell<ProcessInformation>>],
|
||||
) -> Vec<Rc<RefCell<ProcessInformation>>> {
|
||||
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<RefCell<ProcessInformation>>],
|
||||
) -> Vec<Rc<RefCell<ProcessInformation>>> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
let tty = |proc: &Rc<RefCell<ProcessInformation>>| 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
|
||||
}
|
||||
@@ -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<i32> {
|
||||
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<i32> {
|
||||
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<Vec<ProcessInformation>> {
|
||||
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<bool> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
+6
-18
@@ -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::<Vec<_>>();
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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<RefCell<ProcessInformation>>], _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<RefCell<ProcessInformation>>]) {
|
||||
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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user