@@ -17,10 +17,6 @@ use ini::Ini;
1717use native_int_str:: {
1818 Convert , NCvt , NativeIntStr , NativeIntString , NativeStr , from_native_int_representation_owned,
1919} ;
20- #[ cfg( unix) ]
21- use nix:: libc;
22- #[ cfg( unix) ]
23- use nix:: sys:: signal:: { SigHandler :: SigIgn , Signal , signal} ;
2420use std:: borrow:: Cow ;
2521use std:: env;
2622use std:: ffi:: { OsStr , OsString } ;
@@ -29,12 +25,17 @@ use std::io::{self, Write};
2925use std:: os:: unix:: ffi:: OsStrExt ;
3026#[ cfg( unix) ]
3127use std:: os:: unix:: process:: CommandExt ;
28+ #[ cfg( unix) ]
29+ use uucore:: libc:: { SIGKILL , SIGSTOP } ;
30+ #[ cfg( unix) ]
31+ use uucore:: signals:: {
32+ SignalStatus , block_signals, get_signal_status, ignore_signal, reset_signal,
33+ signal_by_name_or_value, signal_name_by_value,
34+ } ;
3235
3336use uucore:: display:: Quotable ;
3437use uucore:: error:: { ExitCode , UError , UResult , USimpleError , UUsageError } ;
3538use uucore:: line_ending:: LineEnding ;
36- #[ cfg( unix) ]
37- use uucore:: signals:: signal_by_name_or_value;
3839use uucore:: translate;
3940use uucore:: { format_usage, show_warning} ;
4041
@@ -84,6 +85,9 @@ mod options {
8485 pub const SPLIT_STRING : & str = "split-string" ;
8586 pub const ARGV0 : & str = "argv0" ;
8687 pub const IGNORE_SIGNAL : & str = "ignore-signal" ;
88+ pub const DEFAULT_SIGNAL : & str = "default-signal" ;
89+ pub const BLOCK_SIGNAL : & str = "block-signal" ;
90+ pub const LIST_SIGNAL_HANDLING : & str = "list-signal-handling" ;
8791}
8892
8993struct Options < ' a > {
@@ -97,6 +101,12 @@ struct Options<'a> {
97101 argv0 : Option < & ' a OsStr > ,
98102 #[ cfg( unix) ]
99103 ignore_signal : Vec < usize > ,
104+ #[ cfg( unix) ]
105+ default_signal : Vec < usize > ,
106+ #[ cfg( unix) ]
107+ block_signal : Vec < usize > ,
108+ #[ cfg( unix) ]
109+ list_signal_handling : bool ,
100110}
101111
102112/// print `name=value` env pairs on screen
@@ -155,11 +165,11 @@ fn parse_signal_value(signal_name: &str) -> UResult<usize> {
155165}
156166
157167#[ cfg( unix) ]
158- fn parse_signal_opt < ' a > ( opts : & mut Options < ' a > , opt : & ' a OsStr ) -> UResult < ( ) > {
168+ fn parse_signal_opt ( signal_vec : & mut Vec < usize > , opt : & OsStr ) -> UResult < ( ) > {
159169 if opt. is_empty ( ) {
160170 return Ok ( ( ) ) ;
161171 }
162- let signals: Vec < & ' a OsStr > = opt
172+ let signals: Vec < & OsStr > = opt
163173 . as_bytes ( )
164174 . split ( |& b| b == b',' )
165175 . map ( OsStr :: from_bytes)
@@ -179,14 +189,35 @@ fn parse_signal_opt<'a>(opts: &mut Options<'a>, opt: &'a OsStr) -> UResult<()> {
179189 ) ) ;
180190 } ;
181191 let sig_val = parse_signal_value ( sig_str) ?;
182- if !opts . ignore_signal . contains ( & sig_val) {
183- opts . ignore_signal . push ( sig_val) ;
192+ if !signal_vec . contains ( & sig_val) {
193+ signal_vec . push ( sig_val) ;
184194 }
185195 }
186196
187197 Ok ( ( ) )
188198}
189199
200+ /// Parse signal option that can be empty (meaning all signals)
201+ #[ cfg( unix) ]
202+ fn parse_signal_opt_or_all ( signal_vec : & mut Vec < usize > , opt : & OsStr ) -> UResult < ( ) > {
203+ if opt. is_empty ( ) {
204+ // Empty means all signals - add all valid signal numbers (1-31 typically)
205+ // Skip SIGKILL and SIGSTOP which cannot be caught or ignored
206+ let sigkill = SIGKILL as usize ;
207+ let sigstop = SIGSTOP as usize ;
208+ for sig_val in 1 ..32 {
209+ if sig_val == sigkill || sig_val == sigstop {
210+ continue ; // SIGKILL and SIGSTOP cannot be modified
211+ }
212+ if !signal_vec. contains ( & sig_val) {
213+ signal_vec. push ( sig_val) ;
214+ }
215+ }
216+ return Ok ( ( ) ) ;
217+ }
218+ parse_signal_opt ( signal_vec, opt)
219+ }
220+
190221fn load_config_file ( opts : & mut Options ) -> UResult < ( ) > {
191222 // NOTE: config files are parsed using an INI parser b/c it's available and compatible with ".env"-style files
192223 // ... * but support for actual INI files, although working, is not intended, nor claimed
@@ -307,9 +338,40 @@ pub fn uu_app() -> Command {
307338 . long ( options:: IGNORE_SIGNAL )
308339 . value_name ( "SIG" )
309340 . action ( ArgAction :: Append )
341+ . num_args ( 0 ..=1 )
342+ . default_missing_value ( "" )
343+ . require_equals ( true )
310344 . value_parser ( ValueParser :: os_string ( ) )
311345 . help ( translate ! ( "env-help-ignore-signal" ) ) ,
312346 )
347+ . arg (
348+ Arg :: new ( options:: DEFAULT_SIGNAL )
349+ . long ( options:: DEFAULT_SIGNAL )
350+ . value_name ( "SIG" )
351+ . action ( ArgAction :: Append )
352+ . num_args ( 0 ..=1 )
353+ . default_missing_value ( "" )
354+ . require_equals ( true )
355+ . value_parser ( ValueParser :: os_string ( ) )
356+ . help ( translate ! ( "env-help-default-signal" ) ) ,
357+ )
358+ . arg (
359+ Arg :: new ( options:: BLOCK_SIGNAL )
360+ . long ( options:: BLOCK_SIGNAL )
361+ . value_name ( "SIG" )
362+ . action ( ArgAction :: Append )
363+ . num_args ( 0 ..=1 )
364+ . default_missing_value ( "" )
365+ . require_equals ( true )
366+ . value_parser ( ValueParser :: os_string ( ) )
367+ . help ( translate ! ( "env-help-block-signal" ) ) ,
368+ )
369+ . arg (
370+ Arg :: new ( options:: LIST_SIGNAL_HANDLING )
371+ . long ( options:: LIST_SIGNAL_HANDLING )
372+ . action ( ArgAction :: SetTrue )
373+ . help ( translate ! ( "env-help-list-signal-handling" ) ) ,
374+ )
313375}
314376
315377pub fn parse_args_from_str ( text : & NativeIntStr ) -> UResult < Vec < NativeIntString > > {
@@ -543,9 +605,23 @@ impl EnvAppData {
543605
544606 apply_specified_env_vars ( & opts) ;
545607
608+ // Apply signal handling in the correct order:
609+ // 1. Reset signals to default
610+ // 2. Set signals to ignore
611+ // 3. Block signals
612+ // 4. List signal handling (if requested)
613+ #[ cfg( unix) ]
614+ apply_default_signal ( & opts) ?;
615+
546616 #[ cfg( unix) ]
547617 apply_ignore_signal ( & opts) ?;
548618
619+ #[ cfg( unix) ]
620+ apply_block_signal ( & opts) ?;
621+
622+ #[ cfg( unix) ]
623+ list_signal_handling ( & opts) ?;
624+
549625 if opts. program . is_empty ( ) {
550626 // no program provided, so just dump all env vars to stdout
551627 print_env ( opts. line_ending ) ;
@@ -705,12 +781,32 @@ fn make_options(matches: &clap::ArgMatches) -> UResult<Options<'_>> {
705781 argv0,
706782 #[ cfg( unix) ]
707783 ignore_signal : vec ! [ ] ,
784+ #[ cfg( unix) ]
785+ default_signal : vec ! [ ] ,
786+ #[ cfg( unix) ]
787+ block_signal : vec ! [ ] ,
788+ #[ cfg( unix) ]
789+ list_signal_handling : matches. get_flag ( options:: LIST_SIGNAL_HANDLING ) ,
708790 } ;
709791
710792 #[ cfg( unix) ]
711- if let Some ( iter) = matches. get_many :: < OsString > ( "ignore-signal" ) {
793+ if let Some ( iter) = matches. get_many :: < OsString > ( options:: IGNORE_SIGNAL ) {
794+ for opt in iter {
795+ parse_signal_opt_or_all ( & mut opts. ignore_signal , opt) ?;
796+ }
797+ }
798+
799+ #[ cfg( unix) ]
800+ if let Some ( iter) = matches. get_many :: < OsString > ( options:: DEFAULT_SIGNAL ) {
712801 for opt in iter {
713- parse_signal_opt ( & mut opts, opt) ?;
802+ parse_signal_opt_or_all ( & mut opts. default_signal , opt) ?;
803+ }
804+ }
805+
806+ #[ cfg( unix) ]
807+ if let Some ( iter) = matches. get_many :: < OsString > ( options:: BLOCK_SIGNAL ) {
808+ for opt in iter {
809+ parse_signal_opt_or_all ( & mut opts. block_signal , opt) ?;
714810 }
715811 }
716812
@@ -821,25 +917,58 @@ fn apply_specified_env_vars(opts: &Options<'_>) {
821917#[ cfg( unix) ]
822918fn apply_ignore_signal ( opts : & Options < ' _ > ) -> UResult < ( ) > {
823919 for & sig_value in & opts. ignore_signal {
824- let sig: Signal = ( sig_value as i32 )
825- . try_into ( )
826- . map_err ( |e| io:: Error :: from_raw_os_error ( e as i32 ) ) ?;
920+ ignore_signal ( sig_value) . map_err ( |err| {
921+ USimpleError :: new (
922+ 125 ,
923+ translate ! ( "env-error-failed-set-signal-action" , "signal" => sig_value, "error" => err. desc( ) ) ,
924+ )
925+ } ) ?;
926+ }
927+ Ok ( ( ) )
928+ }
827929
828- ignore_signal ( sig) ?;
930+ #[ cfg( unix) ]
931+ fn apply_default_signal ( opts : & Options < ' _ > ) -> UResult < ( ) > {
932+ for & sig_value in & opts. default_signal {
933+ reset_signal ( sig_value) . map_err ( |err| {
934+ USimpleError :: new (
935+ 125 ,
936+ translate ! ( "env-error-failed-set-signal-action" , "signal" => sig_value, "error" => err. desc( ) ) ,
937+ )
938+ } ) ?;
829939 }
830940 Ok ( ( ) )
831941}
832942
833943#[ cfg( unix) ]
834- fn ignore_signal ( sig : Signal ) -> UResult < ( ) > {
835- // SAFETY: This is safe because we write the handler for each signal only once, and therefore "the current handler is the default", as the documentation requires it.
836- let result = unsafe { signal ( sig, SigIgn ) } ;
837- if let Err ( err) = result {
838- return Err ( USimpleError :: new (
839- 125 ,
840- translate ! ( "env-error-failed-set-signal-action" , "signal" => ( sig as i32 ) , "error" => err. desc( ) ) ,
841- ) ) ;
944+ fn apply_block_signal ( opts : & Options < ' _ > ) -> UResult < ( ) > {
945+ block_signals ( & opts. block_signal )
946+ . map_err ( |err| USimpleError :: new ( 125 , format ! ( "failed to block signals: {}" , err. desc( ) ) ) )
947+ }
948+
949+ #[ cfg( unix) ]
950+ fn list_signal_handling ( opts : & Options < ' _ > ) -> UResult < ( ) > {
951+ if !opts. list_signal_handling {
952+ return Ok ( ( ) ) ;
842953 }
954+
955+ let stderr = io:: stderr ( ) ;
956+ let mut stderr = stderr. lock ( ) ;
957+
958+ // Check each signal that was modified
959+ for & sig_value in & opts. ignore_signal {
960+ if let Some ( name) = signal_name_by_value ( sig_value) {
961+ if let Ok ( status) = get_signal_status ( sig_value) {
962+ let handler_str = match status {
963+ SignalStatus :: Ignore => "IGNORE" ,
964+ SignalStatus :: Default => "DEFAULT" ,
965+ SignalStatus :: Custom => "HANDLER" ,
966+ } ;
967+ writeln ! ( stderr, "{name:<10} (): {handler_str}" ) . ok ( ) ;
968+ }
969+ }
970+ }
971+
843972 Ok ( ( ) )
844973}
845974
@@ -848,9 +977,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
848977 // Rust ignores SIGPIPE (see https://github.com/rust-lang/rust/issues/62569).
849978 // We restore its default action here.
850979 #[ cfg( unix) ]
851- unsafe {
852- libc:: signal ( libc:: SIGPIPE , libc:: SIG_DFL ) ;
853- }
980+ uucore:: signals:: enable_pipe_errors ( ) . ok ( ) ;
854981 EnvAppData :: default ( ) . run_env ( args)
855982}
856983
0 commit comments