55
66// Common process matcher logic shared by pgrep, pkill and pidwait
77
8- use std:: collections:: HashSet ;
98use std:: hash:: Hash ;
9+ use std:: { collections:: HashSet , io} ;
1010
1111use clap:: { arg, Arg , ArgAction , ArgMatches } ;
1212use regex:: Regex ;
13- use uucore:: error:: { UResult , USimpleError } ;
1413#[ cfg( unix) ]
15- use uucore:: { display:: Quotable , signals:: signal_by_name_or_value} ;
14+ use uucore:: {
15+ display:: Quotable ,
16+ entries:: { grp2gid, usr2uid} ,
17+ signals:: signal_by_name_or_value,
18+ } ;
19+
20+ use uucore:: error:: { UResult , USimpleError } ;
1621
1722use crate :: process:: { walk_process, ProcessInformation , Teletype } ;
1823
@@ -32,6 +37,9 @@ pub struct Settings {
3237 #[ cfg( unix) ]
3338 pub signal : usize ,
3439 pub require_handler : bool ,
40+ pub uid : Option < HashSet < u32 > > ,
41+ pub euid : Option < HashSet < u32 > > ,
42+ pub gid : Option < HashSet < u32 > > ,
3543}
3644
3745pub fn get_match_settings ( matches : & ArgMatches ) -> UResult < Settings > {
@@ -59,14 +67,26 @@ pub fn get_match_settings(matches: &ArgMatches) -> UResult<Settings> {
5967 #[ cfg( unix) ]
6068 signal : parse_signal_value ( matches. get_one :: < String > ( "signal" ) . unwrap ( ) ) ?,
6169 require_handler : matches. get_flag ( "require-handler" ) ,
70+ uid : matches
71+ . get_many :: < u32 > ( "uid" )
72+ . map ( |ids| ids. cloned ( ) . collect ( ) ) ,
73+ euid : matches
74+ . get_many :: < u32 > ( "euid" )
75+ . map ( |ids| ids. cloned ( ) . collect ( ) ) ,
76+ gid : matches
77+ . get_many :: < u32 > ( "group" )
78+ . map ( |ids| ids. cloned ( ) . collect ( ) ) ,
6279 } ;
6380
64- if ( !settings. newest
81+ if !settings. newest
6582 && !settings. oldest
6683 && settings. runstates . is_none ( )
6784 && settings. older . is_none ( )
6885 && settings. parent . is_none ( )
69- && settings. terminal . is_none ( ) )
86+ && settings. terminal . is_none ( )
87+ && settings. uid . is_none ( )
88+ && settings. euid . is_none ( )
89+ && settings. gid . is_none ( )
7090 && pattern. is_empty ( )
7191 {
7292 return Err ( USimpleError :: new (
@@ -183,11 +203,16 @@ fn collect_matched_pids(settings: &Settings) -> Vec<ProcessInformation> {
183203
184204 let parent_matched = any_matches ( & settings. parent , pid. ppid ( ) . unwrap ( ) ) ;
185205
206+ let ids_matched = any_matches ( & settings. uid , pid. uid ( ) . unwrap ( ) )
207+ && any_matches ( & settings. euid , pid. euid ( ) . unwrap ( ) )
208+ && any_matches ( & settings. gid , pid. gid ( ) . unwrap ( ) ) ;
209+
186210 if ( run_state_matched
187211 && pattern_matched
188212 && tty_matched
189213 && older_matched
190- && parent_matched)
214+ && parent_matched
215+ && ids_matched)
191216 ^ settings. inverse
192217 {
193218 tmp_vec. push ( pid) ;
@@ -244,6 +269,36 @@ fn parse_signal_value(signal_name: &str) -> UResult<usize> {
244269 . ok_or_else ( || USimpleError :: new ( 1 , format ! ( "Unknown signal {}" , signal_name. quote( ) ) ) )
245270}
246271
272+ #[ cfg( not( unix) ) ]
273+ pub fn usr2uid ( _name : & str ) -> io:: Result < u32 > {
274+ Err ( io:: Error :: new (
275+ io:: ErrorKind :: InvalidInput ,
276+ "unsupported on this platform" ,
277+ ) )
278+ }
279+
280+ #[ cfg( not( unix) ) ]
281+ pub fn grp2gid ( _name : & str ) -> io:: Result < u32 > {
282+ Err ( io:: Error :: new (
283+ io:: ErrorKind :: InvalidInput ,
284+ "unsupported on this platform" ,
285+ ) )
286+ }
287+
288+ fn parse_uid_or_username ( uid_or_username : & str ) -> io:: Result < u32 > {
289+ uid_or_username
290+ . parse :: < u32 > ( )
291+ . or_else ( |_| usr2uid ( uid_or_username) )
292+ . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: InvalidInput , "invalid user name" ) )
293+ }
294+
295+ fn parse_gid_or_group_name ( gid_or_group_name : & str ) -> io:: Result < u32 > {
296+ gid_or_group_name
297+ . parse :: < u32 > ( )
298+ . or_else ( |_| grp2gid ( gid_or_group_name) )
299+ . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: InvalidInput , "invalid group name" ) )
300+ }
301+
247302#[ allow( clippy:: cognitive_complexity) ]
248303pub fn clap_args ( pattern_help : & ' static str , enable_v_flag : bool ) -> Vec < Arg > {
249304 vec ! [
@@ -258,9 +313,9 @@ pub fn clap_args(pattern_help: &'static str, enable_v_flag: bool) -> Vec<Arg> {
258313 // arg!(-g --pgroup <PGID> "match listed process group IDs")
259314 // .value_delimiter(',')
260315 // .value_parser(clap::value_parser!(u64)),
261- // arg!(-G --group <GID> "match real group IDs")
262- // .value_delimiter(',')
263- // .value_parser(clap::value_parser!(u64) ),
316+ arg!( -G --group <GID > "match real group IDs" )
317+ . value_delimiter( ',' )
318+ . value_parser( parse_gid_or_group_name ) ,
264319 arg!( -i --"ignore-case" "match case insensitively" ) ,
265320 arg!( -n --newest "select most recently started" )
266321 . group( "oldest_newest_inverse" ) ,
@@ -277,12 +332,12 @@ pub fn clap_args(pattern_help: &'static str, enable_v_flag: bool) -> Vec<Arg> {
277332 arg!( --signal <sig> "signal to send (either number or name)" )
278333 . default_value( "SIGTERM" ) ,
279334 arg!( -t --terminal <tty> "match by controlling terminal" ) . value_delimiter( ',' ) ,
280- // arg!(-u --euid <ID> "match by effective IDs")
281- // .value_delimiter(',')
282- // .value_parser(clap::value_parser!(u64) ),
283- // arg!(-U --uid <ID> "match by real IDs")
284- // .value_delimiter(',')
285- // .value_parser(clap::value_parser!(u64) ),
335+ arg!( -u --euid <ID > "match by effective IDs" )
336+ . value_delimiter( ',' )
337+ . value_parser( parse_uid_or_username ) ,
338+ arg!( -U --uid <ID > "match by real IDs" )
339+ . value_delimiter( ',' )
340+ . value_parser( parse_uid_or_username ) ,
286341 arg!( -x --exact "match exactly with the command name" ) ,
287342 // arg!(-F --pidfile <file> "read PIDs from file"),
288343 // arg!(-L --logpidfile "fail if PID file is not locked"),
0 commit comments