@@ -13,7 +13,7 @@ use env;
13
13
use ffi:: OsStr ;
14
14
use fmt;
15
15
use io:: { self , Error , ErrorKind } ;
16
- use libc:: { self , pid_t, c_int , gid_t, uid_t} ;
16
+ use libc:: { self , pid_t, gid_t, uid_t} ;
17
17
use path:: Path ;
18
18
use sys:: fd:: FileDesc ;
19
19
use sys:: fs:: { File , OpenOptions } ;
@@ -145,33 +145,79 @@ impl Command {
145
145
146
146
pub fn spawn ( & mut self , default : Stdio , needs_stdin : bool )
147
147
-> io:: Result < ( Process , StdioPipes ) > {
148
- if self . saw_nul {
149
- return Err ( io:: Error :: new ( ErrorKind :: InvalidInput ,
150
- "nul byte found in provided data" ) ) ;
151
- }
152
-
153
- let ( ours, theirs) = self . setup_io ( default, needs_stdin) ?;
154
-
155
- let pid = unsafe {
156
- match cvt ( libc:: clone ( libc:: CLONE_VFORK ) ) ? {
157
- 0 => {
158
- let err = self . do_exec ( theirs) ;
159
- let _ = libc:: exit ( ( -err. raw_os_error ( ) . unwrap_or ( libc:: EINVAL ) ) as usize ) ;
160
- unreachable ! ( ) ;
161
- }
162
- n => n as pid_t ,
163
- }
164
- } ;
165
-
166
- let mut status_mux = 0 ;
167
- if cvt ( libc:: waitpid ( pid, & mut status_mux, libc:: WNOHANG ) ) ? == pid {
168
- match libc:: Error :: demux ( status_mux) {
169
- Ok ( status) => Ok ( ( Process { pid : pid, status : Some ( ExitStatus :: from ( status as c_int ) ) } , ours) ) ,
170
- Err ( err) => Err ( io:: Error :: from_raw_os_error ( err. errno ) ) ,
171
- }
172
- } else {
173
- Ok ( ( Process { pid : pid, status : None } , ours) )
174
- }
148
+ const CLOEXEC_MSG_FOOTER : & ' static [ u8 ] = b"NOEX" ;
149
+
150
+ if self . saw_nul {
151
+ return Err ( io:: Error :: new ( ErrorKind :: InvalidInput ,
152
+ "nul byte found in provided data" ) ) ;
153
+ }
154
+
155
+ let ( ours, theirs) = self . setup_io ( default, needs_stdin) ?;
156
+ let ( input, output) = pipe:: anon_pipe ( ) ?;
157
+
158
+ let pid = unsafe {
159
+ match cvt ( libc:: clone ( 0 ) ) ? {
160
+ 0 => {
161
+ drop ( input) ;
162
+ let err = self . do_exec ( theirs) ;
163
+ let errno = err. raw_os_error ( ) . unwrap_or ( libc:: EINVAL ) as u32 ;
164
+ let bytes = [
165
+ ( errno >> 24 ) as u8 ,
166
+ ( errno >> 16 ) as u8 ,
167
+ ( errno >> 8 ) as u8 ,
168
+ ( errno >> 0 ) as u8 ,
169
+ CLOEXEC_MSG_FOOTER [ 0 ] , CLOEXEC_MSG_FOOTER [ 1 ] ,
170
+ CLOEXEC_MSG_FOOTER [ 2 ] , CLOEXEC_MSG_FOOTER [ 3 ]
171
+ ] ;
172
+ // pipe I/O up to PIPE_BUF bytes should be atomic, and then
173
+ // we want to be sure we *don't* run at_exit destructors as
174
+ // we're being torn down regardless
175
+ assert ! ( output. write( & bytes) . is_ok( ) ) ;
176
+ let _ = libc:: exit ( 1 ) ;
177
+ panic ! ( "failed to exit" ) ;
178
+ }
179
+ n => n,
180
+ }
181
+ } ;
182
+
183
+ let mut p = Process { pid : pid, status : None } ;
184
+ drop ( output) ;
185
+ let mut bytes = [ 0 ; 8 ] ;
186
+
187
+ // loop to handle EINTR
188
+ loop {
189
+ match input. read ( & mut bytes) {
190
+ Ok ( 0 ) => return Ok ( ( p, ours) ) ,
191
+ Ok ( 8 ) => {
192
+ assert ! ( combine( CLOEXEC_MSG_FOOTER ) == combine( & bytes[ 4 .. 8 ] ) ,
193
+ "Validation on the CLOEXEC pipe failed: {:?}" , bytes) ;
194
+ let errno = combine ( & bytes[ 0 .. 4 ] ) ;
195
+ assert ! ( p. wait( ) . is_ok( ) ,
196
+ "wait() should either return Ok or panic" ) ;
197
+ return Err ( Error :: from_raw_os_error ( errno) )
198
+ }
199
+ Err ( ref e) if e. kind ( ) == ErrorKind :: Interrupted => { }
200
+ Err ( e) => {
201
+ assert ! ( p. wait( ) . is_ok( ) ,
202
+ "wait() should either return Ok or panic" ) ;
203
+ panic ! ( "the CLOEXEC pipe failed: {:?}" , e)
204
+ } ,
205
+ Ok ( ..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
206
+ assert ! ( p. wait( ) . is_ok( ) ,
207
+ "wait() should either return Ok or panic" ) ;
208
+ panic ! ( "short read on the CLOEXEC pipe" )
209
+ }
210
+ }
211
+ }
212
+
213
+ fn combine ( arr : & [ u8 ] ) -> i32 {
214
+ let a = arr[ 0 ] as u32 ;
215
+ let b = arr[ 1 ] as u32 ;
216
+ let c = arr[ 2 ] as u32 ;
217
+ let d = arr[ 3 ] as u32 ;
218
+
219
+ ( ( a << 24 ) | ( b << 16 ) | ( c << 8 ) | ( d << 0 ) ) as i32
220
+ }
175
221
}
176
222
177
223
pub fn exec ( & mut self , default : Stdio ) -> io:: Error {
@@ -378,11 +424,11 @@ impl fmt::Debug for Command {
378
424
379
425
/// Unix exit statuses
380
426
#[ derive( PartialEq , Eq , Clone , Copy , Debug ) ]
381
- pub struct ExitStatus ( c_int ) ;
427
+ pub struct ExitStatus ( i32 ) ;
382
428
383
429
impl ExitStatus {
384
430
fn exited ( & self ) -> bool {
385
- true
431
+ self . 0 & 0x7F == 0
386
432
}
387
433
388
434
pub fn success ( & self ) -> bool {
@@ -391,23 +437,23 @@ impl ExitStatus {
391
437
392
438
pub fn code ( & self ) -> Option < i32 > {
393
439
if self . exited ( ) {
394
- Some ( self . 0 )
440
+ Some ( ( self . 0 >> 8 ) & 0xFF )
395
441
} else {
396
442
None
397
443
}
398
444
}
399
445
400
446
pub fn signal ( & self ) -> Option < i32 > {
401
447
if !self . exited ( ) {
402
- Some ( self . 0 )
448
+ Some ( self . 0 & 0x7F )
403
449
} else {
404
450
None
405
451
}
406
452
}
407
453
}
408
454
409
- impl From < c_int > for ExitStatus {
410
- fn from ( a : c_int ) -> ExitStatus {
455
+ impl From < i32 > for ExitStatus {
456
+ fn from ( a : i32 ) -> ExitStatus {
411
457
ExitStatus ( a)
412
458
}
413
459
}
0 commit comments