char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
f4a0f5b
main
1use std:: io; 2use std:: os:: unix:: process:: ExitStatusExt ; 3use std:: process:: ExitStatus ; 4use std:: sync:: OnceLock ; 5 6const SIGNALS : [( & str , libc:: c_int ); 16 ] =[ 7( "SIGHUP" , libc:: SIGHUP ), 8( "SIGINT" , libc:: SIGINT ), 9( "SIGQUIT" , libc:: SIGQUIT ), 10( "SIGABRT" , libc:: SIGABRT ), 11( "SIGKILL" , libc:: SIGKILL ), 12( "SIGUSR1" , libc:: SIGUSR1 ), 13( "SIGUSR2" , libc:: SIGUSR2 ), 14( "SIGPIPE" , libc:: SIGPIPE ), 15( "SIGALRM" , libc:: SIGALRM ), 16( "SIGTERM" , libc:: SIGTERM ), 17( "SIGCONT" , libc:: SIGCONT ), 18( "SIGSTOP" , libc:: SIGSTOP ), 19( "SIGTSTP" , libc:: SIGTSTP ), 20( "SIGTTIN" , libc:: SIGTTIN ), 21( "SIGTTOU" , libc:: SIGTTOU ), 22( "SIGWINCH" , libc:: SIGWINCH ), 23]; 24 25pub ( crate ) fn signal_number ( name : & str ) -> io:: Result < libc:: c_int > { 26SIGNALS 27. iter () 28. find ( |( text, _) |* text == name) 29. map ( |( _, number) |* number) 30. ok_or_else ( || io:: Error :: new ( io:: ErrorKind :: InvalidInput , "Unsupported subprocess signal" )) 31} 32 33/// Whether this names a real (if not necessarily listenable) signal. 34pub fn known_signal ( name : & str ) ->bool { 35SIGNALS . iter (). any ( |( text, _) |* text == name) 36} 37 38pub fn validate_signal ( name : & str ) -> io:: Result <()> { 39signal_number ( name). map ( drop) 40} 41 42pub fn exit_signal ( status : & ExitStatus ) ->Option < String > { 43let number = status. signal () ?; 44Some ( 45SIGNALS 46. iter () 47. find ( |( _, value) |* value == number) 48. map_or_else ( ||format! ( "SIG{number}" ), |( name, _) |( * name). into ()), 49) 50} 51 52/// A listenable signal's inherited disposition, snapshotted once at 53/// process start. Every fate decision consults the snapshot instead of a 54/// live query, which later installs (supervisor, feeds, owners) would 55/// otherwise corrupt. 56# [ derive ( Clone , Copy , PartialEq )] 57pub enum Prior { 58Default , 59Ignored , 60Owned , 61} 62 63/// The signals whose startup disposition the snapshot records: every 64/// signal listener feeds can bind plus the supervisor's own two. 65const SNAPSHOT_SIGNALS : [ libc:: c_int ; 6 ] =[ 66 libc:: SIGINT , 67 libc:: SIGTERM , 68 libc:: SIGHUP , 69 libc:: SIGUSR1 , 70 libc:: SIGUSR2 , 71 libc:: SIGWINCH , 72]; 73 74static ORIGINALS : OnceLock <[( libc:: c_int , Prior ); 6 ]> =OnceLock :: new (); 75 76/// Records each listenable signal's inherited disposition. Call once 77/// at process start, before the supervisor, feeds, or owners install 78/// anything; later installs must not move the baseline. 79pub fn snapshot_originals () { 80let _ =ORIGINALS . get_or_init ( ||{ 81SNAPSHOT_SIGNALS . map ( |number|{ 82let mut old: libc:: sigaction =unsafe { std:: mem:: zeroed () }; 83unsafe { 84 libc:: sigaction ( number, std:: ptr:: null (), & mut old); 85} 86( 87 number, 88if old. sa_sigaction == libc:: SIG_IGN { 89Prior :: Ignored 90} else if old. sa_sigaction == libc:: SIG_DFL { 91Prior :: Default 92} else { 93Prior :: Owned 94}, 95) 96}) 97}); 98} 99/// A listenable signal's startup disposition. Falls back to a live 100/// query when the process never snapshotted (in-process tests). 101pub fn original_prior ( number : libc:: c_int ) ->Prior { 102if let Some ( found) =ORIGINALS . get (). and_then ( |originals|{ 103 originals 104. iter () 105. find ( |( signal, _) |* signal == number) 106. map ( |( _, prior) |* prior) 107}) { 108return found; 109} 110let mut old: libc:: sigaction =unsafe { std:: mem:: zeroed () }; 111unsafe { 112 libc:: sigaction ( number, std:: ptr:: null (), & mut old); 113} 114if old. sa_sigaction == libc:: SIG_IGN { 115Prior :: Ignored 116} else if old. sa_sigaction == libc:: SIG_DFL { 117Prior :: Default 118} else { 119Prior :: Owned 120} 121} 122/// Whether this signal was ignored at process start. Consult the 123/// snapshot, never the live disposition. 124pub fn originally_ignored ( number : libc:: c_int ) ->bool { 125original_prior ( number) ==Prior :: Ignored 126} 127 128pub ( crate ) fn send ( pid : u32 , group : bool , number : libc:: c_int ) -> std:: io:: Result < bool > { 129let target =if group{ 130 -( pidas libc:: pid_t ) 131} else { 132 pidas libc:: pid_t 133}; 134if unsafe { libc:: kill ( target, number) } ==0 { 135return Ok ( true ); 136} 137let error = std:: io:: Error :: last_os_error (); 138if error. raw_os_error () ==Some ( libc:: ESRCH ) { 139Ok ( false ) 140} else { 141Err ( error) 142} 143}