Skip to content

Commit aa9c3c1

Browse files
committed
ps: Support more process selection flags
1 parent 6c674ac commit aa9c3c1

File tree

3 files changed

+300
-24
lines changed

3 files changed

+300
-24
lines changed

src/uu/ps/src/process_selection.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,22 @@ pub struct ProcessSelectionSettings {
4747
/// - `-x` Lift "must have a tty" restriction.
4848
pub dont_require_tty: bool,
4949

50+
/// - `-C` Select by command name
51+
pub command_names: Option<HashSet<String>>,
5052
/// - `-p, --pid` Select specific process IDs
5153
pub pids: Option<HashSet<usize>>,
54+
/// - `--ppid` Select specific parent process IDs
55+
pub ppids: Option<HashSet<usize>>,
56+
/// - `--sid` Select specific session IDs
57+
pub sids: Option<HashSet<usize>>,
58+
/// - `-G, --Group` Select by real group ID or name
59+
pub real_groups: Option<HashSet<u32>>,
60+
/// - `-g, --group` Select by effective group ID or name
61+
pub eff_groups: Option<HashSet<u32>>,
62+
/// - `-U, --User` Select by real user ID or name
63+
pub real_users: Option<HashSet<u32>>,
64+
/// - `-u, --user` Select by effective user ID or name
65+
pub eff_users: Option<HashSet<u32>>,
5266

5367
/// - `-r` Restrict the selection to only running processes.
5468
pub only_running: bool,
@@ -64,9 +78,30 @@ impl ProcessSelectionSettings {
6478
select_non_session_leaders_with_tty: matches.get_flag("a"),
6579
select_non_session_leaders: matches.get_flag("d"),
6680
dont_require_tty: matches.get_flag("x"),
81+
command_names: matches
82+
.get_many::<Vec<String>>("command")
83+
.map(|xs| xs.flatten().cloned().collect()),
6784
pids: matches
6885
.get_many::<Vec<usize>>("pid")
6986
.map(|xs| xs.flatten().copied().collect()),
87+
ppids: matches
88+
.get_many::<Vec<usize>>("ppid")
89+
.map(|xs| xs.flatten().copied().collect()),
90+
sids: matches
91+
.get_many::<Vec<usize>>("sid")
92+
.map(|xs| xs.flatten().copied().collect()),
93+
real_groups: matches
94+
.get_many::<Vec<u32>>("real-group")
95+
.map(|xs| xs.flatten().copied().collect()),
96+
eff_groups: matches
97+
.get_many::<Vec<u32>>("effective-group")
98+
.map(|xs| xs.flatten().copied().collect()),
99+
real_users: matches
100+
.get_many::<Vec<u32>>("real-user")
101+
.map(|xs| xs.flatten().copied().collect()),
102+
eff_users: matches
103+
.get_many::<Vec<u32>>("effective-user")
104+
.map(|xs| xs.flatten().copied().collect()),
70105
only_running: matches.get_flag("r"),
71106
negate_selection: matches.get_flag("deselect"),
72107
}
@@ -86,8 +121,30 @@ impl ProcessSelectionSettings {
86121
return Ok(true);
87122
}
88123

89-
if let Some(ref pids) = self.pids {
90-
return Ok(pids.contains(&process.pid));
124+
// Flags in this group seem to cause rest of the flags to be ignored
125+
let mut matched: Option<bool> = None;
126+
fn update_match<T, U>(
127+
matched: &mut Option<bool>,
128+
set_opt: &Option<HashSet<T>>,
129+
value: U,
130+
) where
131+
T: std::cmp::Eq + std::hash::Hash + std::borrow::Borrow<U>,
132+
U: std::cmp::Eq + std::hash::Hash,
133+
{
134+
if let Some(ref set) = set_opt {
135+
*matched.get_or_insert_default() |= set.contains(&value);
136+
}
137+
}
138+
update_match(&mut matched, &self.command_names, process.name().unwrap());
139+
update_match(&mut matched, &self.pids, process.pid);
140+
update_match(&mut matched, &self.ppids, process.ppid().unwrap() as usize);
141+
update_match(&mut matched, &self.sids, process.sid().unwrap() as usize);
142+
update_match(&mut matched, &self.real_users, process.uid().unwrap());
143+
update_match(&mut matched, &self.eff_users, process.euid().unwrap());
144+
update_match(&mut matched, &self.real_groups, process.gid().unwrap());
145+
update_match(&mut matched, &self.eff_groups, process.egid().unwrap());
146+
if let Some(m) = matched {
147+
return Ok(m);
91148
}
92149

93150
if self.select_non_session_leaders_with_tty {

src/uu/ps/src/ps.rs

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use prettytable::{format::consts::FORMAT_CLEAN, Row, Table};
2222
use process_selection::ProcessSelectionSettings;
2323
use std::cell::RefCell;
2424
use uucore::{
25+
entries::{grp2gid, usr2uid},
2526
error::{UError, UResult, USimpleError},
2627
format_usage, help_about, help_usage,
2728
};
@@ -138,15 +139,45 @@ fn collect_format(
138139
Ok(collect)
139140
}
140141

141-
fn parse_numeric_list(s: &str) -> Result<Vec<usize>, String> {
142+
fn split_arg_list(s: &str) -> impl Iterator<Item = &str> {
142143
s.split(|c: char| c.is_whitespace() || c == ',')
144+
}
145+
146+
fn parse_numeric_list(s: &str) -> Result<Vec<usize>, String> {
147+
split_arg_list(s)
143148
.map(|word| {
144149
word.parse::<usize>()
145150
.map_err(|_| format!("invalid number: '{}'", word))
146151
})
147152
.collect()
148153
}
149154

155+
fn parse_uid_list(s: &str) -> Result<Vec<u32>, String> {
156+
split_arg_list(s)
157+
.map(|uid_or_username| {
158+
uid_or_username
159+
.parse::<u32>()
160+
.or_else(|_| usr2uid(uid_or_username))
161+
.map_err(|_| format!("invalid user name '{}'", uid_or_username))
162+
})
163+
.collect()
164+
}
165+
166+
fn parse_gid_list(s: &str) -> Result<Vec<u32>, String> {
167+
split_arg_list(s)
168+
.map(|gid_or_group_name| {
169+
gid_or_group_name
170+
.parse::<u32>()
171+
.or_else(|_| grp2gid(gid_or_group_name))
172+
.map_err(|_| format!("invalid group name '{}'", gid_or_group_name))
173+
})
174+
.collect()
175+
}
176+
177+
fn parse_command_list(s: &str) -> Result<Vec<String>, String> {
178+
Ok(split_arg_list(s).map(|part| part.to_string()).collect())
179+
}
180+
150181
#[allow(clippy::cognitive_complexity)]
151182
pub fn uu_app() -> Command {
152183
Command::new(uucore::util_name())
@@ -271,6 +302,13 @@ pub fn uu_app() -> Command {
271302
.action(ArgAction::SetTrue)
272303
.help("do not print header at all"),
273304
)
305+
.arg(
306+
Arg::new("command")
307+
.short('C')
308+
.action(ArgAction::Append)
309+
.value_parser(parse_command_list)
310+
.help("select by command name"),
311+
)
274312
.arg(
275313
Arg::new("pid")
276314
.short('p')
@@ -279,33 +317,57 @@ pub fn uu_app() -> Command {
279317
.value_parser(parse_numeric_list)
280318
.help("select by process ID"),
281319
)
320+
.arg(
321+
Arg::new("ppid")
322+
.long("ppid")
323+
.action(ArgAction::Append)
324+
.value_parser(parse_numeric_list)
325+
.help("select by parent process ID"),
326+
)
327+
.arg(
328+
Arg::new("sid")
329+
.long("sid")
330+
.action(ArgAction::Append)
331+
.value_parser(parse_numeric_list)
332+
.help("select by session ID"),
333+
)
334+
.arg(
335+
Arg::new("real-group")
336+
.short('G')
337+
.long("Group")
338+
.action(ArgAction::Append)
339+
.value_parser(parse_gid_list)
340+
.help("select by real group ID (RGID) or name"),
341+
)
342+
.arg(
343+
Arg::new("effective-group")
344+
.short('g')
345+
.long("group")
346+
.action(ArgAction::Append)
347+
.value_parser(parse_gid_list)
348+
.help("select by effective group ID (EGID) or name"),
349+
)
350+
.arg(
351+
Arg::new("real-user")
352+
.short('U')
353+
.long("User")
354+
.action(ArgAction::Append)
355+
.value_parser(parse_uid_list)
356+
.help("select by real user ID (RUID) or name"),
357+
)
358+
.arg(
359+
Arg::new("effective-user")
360+
.long("user")
361+
.action(ArgAction::Append)
362+
.value_parser(parse_uid_list)
363+
.help("select by effective user ID (EUID) or name"),
364+
)
282365
// .args([
283-
// Arg::new("command").short('c').help("command name"),
284-
// Arg::new("GID")
285-
// .short('G')
286-
// .long("Group")
287-
// .help("real group id or name"),
288-
// Arg::new("group")
289-
// .short('g')
290-
// .long("group")
291-
// .help("session or effective group name"),
292366
// Arg::new("pPID").long("ppid").help("parent process id"),
293367
// Arg::new("qPID")
294368
// .short('q')
295369
// .long("quick-pid")
296370
// .help("process id"),
297-
// Arg::new("session")
298-
// .short('s')
299-
// .long("sid")
300-
// .help("session id"),
301371
// Arg::new("t").short('t').long("tty").help("terminal"),
302-
// Arg::new("eUID")
303-
// .short('u')
304-
// .long("user")
305-
// .help("effective user id or name"),
306-
// Arg::new("rUID")
307-
// .short('U')
308-
// .long("User")
309-
// .help("real user id or name"),
310372
// ])
311373
}

0 commit comments

Comments
 (0)