Skip to content

Commit 9c12e49

Browse files
authored
Merge pull request #559 from dezgeg/ps_refact
ps: Refactor process selection + support new flags
2 parents f636cb9 + f1b89bc commit 9c12e49

File tree

9 files changed

+254
-153
lines changed

9 files changed

+254
-153
lines changed

src/uu/pgrep/src/process_matcher.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ fn try_get_pattern_from(matches: &ArgMatches) -> UResult<String> {
209209
pattern
210210
};
211211

212-
Ok(pattern.to_string())
212+
Ok(pattern.clone())
213213
}
214214

215215
fn any_matches<T: Eq + Hash>(optional_ids: &Option<HashSet<T>>, id: T) -> bool {

src/uu/ps/src/collector.rs

Lines changed: 0 additions & 107 deletions
This file was deleted.

src/uu/ps/src/mapping.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub(crate) fn collect_code_mapping(formats: &[OptionalKeyValue]) -> Vec<(String,
1515
let key = it.key().to_string();
1616
match it.value() {
1717
Some(value) => (key, value.clone()),
18-
None => (key.clone(), mapping.get(&key).unwrap().to_string()),
18+
None => (key.clone(), mapping.get(&key).unwrap().clone()),
1919
}
2020
})
2121
.collect()
@@ -104,6 +104,13 @@ pub(crate) fn vm_format_codes() -> Vec<String> {
104104
.to_vec()
105105
}
106106

107+
/// Returns the format codes used when BSD flags (e.g. -x) are used.
108+
pub(crate) fn bsd_format_codes() -> Vec<String> {
109+
["pid", "tname", "stat", "time", "command"]
110+
.map(Into::into)
111+
.to_vec()
112+
}
113+
107114
/// Returns the register format codes (for -X flag).
108115
pub(crate) fn register_format_codes() -> Vec<String> {
109116
[

src/uu/ps/src/process_selection.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// This file is part of the uutils procps package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
use clap::ArgMatches;
7+
use std::collections::HashSet;
8+
use uu_pgrep::process::{walk_process, ProcessInformation, RunState, Teletype};
9+
use uucore::error::UResult;
10+
11+
#[cfg(target_family = "unix")]
12+
use nix::errno::Errno;
13+
14+
// TODO: Temporary add to this file, this function will add to uucore.
15+
#[cfg(not(target_os = "redox"))]
16+
#[cfg(target_family = "unix")]
17+
fn getsid(pid: i32) -> Option<i32> {
18+
unsafe {
19+
let result = libc::getsid(pid);
20+
if Errno::last() == Errno::UnknownErrno {
21+
Some(result)
22+
} else {
23+
None
24+
}
25+
}
26+
}
27+
28+
// TODO: Temporary add to this file, this function will add to uucore.
29+
#[cfg(target_family = "windows")]
30+
fn getsid(_pid: i32) -> Option<i32> {
31+
Some(0)
32+
}
33+
34+
fn is_session_leader(process: &ProcessInformation) -> bool {
35+
let pid = process.pid as i32;
36+
getsid(pid) == Some(pid)
37+
}
38+
39+
pub struct ProcessSelectionSettings {
40+
/// - `-A` Select all processes. Identical to `-e`.
41+
pub select_all: bool,
42+
/// - `-a` Select all processes except both session leaders (see getsid(2)) and processes not associated with a terminal.
43+
pub select_non_session_leaders_with_tty: bool,
44+
/// - `-d` Select all processes except session leaders.
45+
pub select_non_session_leaders: bool,
46+
47+
/// - '-x' Lift "must have a tty" restriction.
48+
pub dont_require_tty: bool,
49+
50+
/// Select specific process IDs (-p, --pid)
51+
pub pids: Option<HashSet<usize>>,
52+
53+
/// - `-r` Restrict the selection to only running processes.
54+
pub only_running: bool,
55+
56+
/// - `--deselect` Negates the selection.
57+
pub negate_selection: bool,
58+
}
59+
60+
impl ProcessSelectionSettings {
61+
pub fn from_matches(matches: &ArgMatches) -> Self {
62+
Self {
63+
select_all: matches.get_flag("A"),
64+
select_non_session_leaders_with_tty: matches.get_flag("a"),
65+
select_non_session_leaders: matches.get_flag("d"),
66+
dont_require_tty: matches.get_flag("x"),
67+
pids: matches
68+
.get_many::<Vec<usize>>("pid")
69+
.map(|xs| xs.flatten().copied().collect()),
70+
only_running: matches.get_flag("r"),
71+
negate_selection: matches.get_flag("deselect"),
72+
}
73+
}
74+
75+
pub fn select_processes(self) -> UResult<Vec<ProcessInformation>> {
76+
let mut current_process = ProcessInformation::current_process_info().unwrap();
77+
let current_tty = current_process.tty();
78+
let current_euid = current_process.euid().unwrap();
79+
80+
let matches_criteria = |process: &mut ProcessInformation| -> UResult<bool> {
81+
if self.only_running && !process.run_state().is_ok_and(|x| x == RunState::Running) {
82+
return Ok(false);
83+
}
84+
85+
if let Some(ref pids) = self.pids {
86+
return Ok(pids.contains(&process.pid));
87+
}
88+
89+
if self.select_all {
90+
return Ok(true);
91+
}
92+
93+
if self.select_non_session_leaders_with_tty {
94+
return Ok(!is_session_leader(process) && process.tty() != Teletype::Unknown);
95+
}
96+
97+
if self.select_non_session_leaders {
98+
return Ok(!is_session_leader(process));
99+
}
100+
101+
// Default behavior: select processes with same effective user ID and same tty (except -x removes tty restriction)
102+
Ok(process.euid().unwrap() == current_euid
103+
&& (self.dont_require_tty || process.tty() == current_tty))
104+
};
105+
106+
let mut selected = vec![];
107+
for mut process in walk_process() {
108+
if matches_criteria(&mut process)? ^ self.negate_selection {
109+
selected.push(process);
110+
}
111+
}
112+
113+
Ok(selected)
114+
}
115+
}

0 commit comments

Comments
 (0)