@@ -9,7 +9,6 @@ use std::{
9
9
time:: Duration ,
10
10
} ;
11
11
12
- use crate :: log:: { dev_info, dev_warn} ;
13
12
use crate :: system:: {
14
13
fork, getpgid,
15
14
interface:: ProcessId ,
@@ -18,13 +17,18 @@ use crate::system::{
18
17
term:: { set_controlling_terminal, tcgetpgrp, tcsetpgrp} ,
19
18
wait:: { waitpid, WaitError , WaitOptions } ,
20
19
} ;
20
+ use crate :: {
21
+ exec:: event:: StopReason ,
22
+ log:: { dev_info, dev_warn} ,
23
+ } ;
21
24
22
25
use signal_hook:: consts:: * ;
23
26
24
27
use super :: {
25
28
backchannel:: { MonitorBackchannel , MonitorMessage , ParentMessage } ,
26
29
event:: { EventClosure , EventDispatcher } ,
27
30
io_util:: { retry_while_interrupted, was_interrupted} ,
31
+ ExitReason ,
28
32
} ;
29
33
use super :: { cond_fmt, signal_fmt} ;
30
34
@@ -103,10 +107,17 @@ pub(super) fn exec_monitor(
103
107
// FIXME (ogsudo): Set the command as the foreground process for the follower.
104
108
105
109
// Start the event loop.
106
- dispatcher. event_loop ( & mut closure) ;
110
+ let reason = dispatcher. event_loop ( & mut closure) ;
107
111
// FIXME (ogsudo): Terminate the command using `killpg` if it's not terminated.
108
112
// FIXME (ogsudo): Take the controlling tty so the command's children don't receive SIGHUP when we exit.
109
- // FIXME (ogsudo): Send the command status back to the parent.
113
+
114
+ match reason {
115
+ StopReason :: Break ( ( ) ) => { }
116
+ StopReason :: Exit ( exit_reason) => {
117
+ closure. backchannel . send ( & exit_reason. into ( ) ) . ok ( ) ;
118
+ }
119
+ }
120
+
110
121
// FIXME (ogsudo): The tty is restored here if selinux is available.
111
122
112
123
drop ( closure) ;
@@ -180,6 +191,7 @@ impl<'a> MonitorClosure<'a> {
180
191
// There's something wrong with the backchannel, break the event loop
181
192
Err ( err) => {
182
193
dev_warn ! ( "monitor could not read from backchannel: {}" , err) ;
194
+ // FIXME: maybe the break reason should be `io::Error` instead.
183
195
dispatcher. set_break ( ( ) ) ;
184
196
self . backchannel . send ( & err. into ( ) ) . unwrap ( ) ;
185
197
}
@@ -198,7 +210,7 @@ impl<'a> MonitorClosure<'a> {
198
210
}
199
211
}
200
212
201
- fn handle_sigchld ( & mut self , command_pid : ProcessId ) {
213
+ fn handle_sigchld ( & mut self , command_pid : ProcessId , dispatcher : & mut EventDispatcher < Self > ) {
202
214
let status = loop {
203
215
match waitpid ( command_pid, WaitOptions :: new ( ) . untraced ( ) . no_hang ( ) ) {
204
216
Ok ( ( _pid, status) ) => break status,
@@ -211,25 +223,24 @@ impl<'a> MonitorClosure<'a> {
211
223
dev_info ! ( "command ({command_pid}) exited with status code {exit_code}" ) ;
212
224
// The command did exit, set it's PID to `None`.
213
225
self . command_pid = None ;
214
- self . backchannel
215
- . send ( & ParentMessage :: CommandExit ( exit_code) )
216
- . ok ( ) ;
226
+ dispatcher. set_exit ( ExitReason :: Code ( exit_code) )
217
227
} else if let Some ( signal) = status. term_signal ( ) {
218
228
dev_info ! (
219
229
"command ({command_pid}) was terminated by {}" ,
220
230
signal_fmt( signal) ,
221
231
) ;
222
232
// The command was terminated, set it's PID to `None`.
223
233
self . command_pid = None ;
224
- self . backchannel
225
- . send ( & ParentMessage :: CommandSignal ( signal) )
226
- . ok ( ) ;
227
- } else if let Some ( _signal) = status. stop_signal ( ) {
228
- // FIXME: we should save the foreground process group ID so we can restore it later.
234
+ dispatcher. set_exit ( ExitReason :: Signal ( signal) )
235
+ } else if let Some ( signal) = status. stop_signal ( ) {
229
236
dev_info ! (
230
237
"command ({command_pid}) was stopped by {}" ,
231
- signal_fmt( _signal ) ,
238
+ signal_fmt( signal ) ,
232
239
) ;
240
+ // FIXME: we should save the foreground process group ID so we can restore it later.
241
+ self . backchannel
242
+ . send ( & ParentMessage :: CommandSignal ( signal) )
243
+ . ok ( ) ;
233
244
} else if status. did_continue ( ) {
234
245
dev_info ! ( "command ({command_pid}) continued execution" ) ;
235
246
} else {
@@ -308,7 +319,7 @@ fn is_self_terminating(
308
319
309
320
impl < ' a > EventClosure for MonitorClosure < ' a > {
310
321
type Break = ( ) ;
311
- type Exit = ( ) ;
322
+ type Exit = ExitReason ;
312
323
313
324
fn on_signal ( & mut self , info : SignalInfo , dispatcher : & mut EventDispatcher < Self > ) {
314
325
dev_info ! (
@@ -325,12 +336,7 @@ impl<'a> EventClosure for MonitorClosure<'a> {
325
336
} ;
326
337
327
338
match info. signal ( ) {
328
- SIGCHLD => {
329
- self . handle_sigchld ( command_pid) ;
330
- if self . command_pid . is_none ( ) {
331
- dispatcher. set_exit ( ( ) ) ;
332
- }
333
- }
339
+ SIGCHLD => self . handle_sigchld ( command_pid, dispatcher) ,
334
340
// Skip the signal if it was sent by the user and it is self-terminating.
335
341
_ if info. is_user_signaled ( )
336
342
&& is_self_terminating ( info. pid ( ) , command_pid, self . command_pgrp ) => { }
0 commit comments