@@ -34,6 +34,11 @@ impl Command {
3434 }
3535
3636 let ( ours, theirs) = self . setup_io ( default, needs_stdin) ?;
37+
38+ if let Some ( ret) = self . posix_spawn ( & theirs, envp. as_ref ( ) ) ? {
39+ return Ok ( ( ret, ours) )
40+ }
41+
3742 let ( input, output) = sys:: pipe:: anon_pipe ( ) ?;
3843
3944 let pid = unsafe {
@@ -229,6 +234,119 @@ impl Command {
229234 libc:: execvp ( self . get_argv ( ) [ 0 ] , self . get_argv ( ) . as_ptr ( ) ) ;
230235 io:: Error :: last_os_error ( )
231236 }
237+
238+ #[ cfg( not( any( target_os = "macos" , target_os = "freebsd" ,
239+ all( target_os = "linux" , target_env = "gnu" ) ) ) ) ]
240+ fn posix_spawn ( & mut self , _: & ChildPipes , _: Option < & CStringArray > )
241+ -> io:: Result < Option < Process > >
242+ {
243+ Ok ( None )
244+ }
245+
246+ // Only support platforms for which posix_spawn() can return ENOENT
247+ // directly.
248+ #[ cfg( any( target_os = "macos" , target_os = "freebsd" ,
249+ all( target_os = "linux" , target_env = "gnu" ) ) ) ]
250+ fn posix_spawn ( & mut self , stdio : & ChildPipes , envp : Option < & CStringArray > )
251+ -> io:: Result < Option < Process > >
252+ {
253+ use mem;
254+ use sys;
255+
256+ if self . get_cwd ( ) . is_some ( ) ||
257+ self . get_gid ( ) . is_some ( ) ||
258+ self . get_uid ( ) . is_some ( ) ||
259+ self . env_saw_path ( ) ||
260+ self . get_closures ( ) . len ( ) != 0 {
261+ return Ok ( None )
262+ }
263+
264+ // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly.
265+ #[ cfg( all( target_os = "linux" , target_env = "gnu" ) ) ]
266+ {
267+ if let Some ( version) = sys:: os:: glibc_version ( ) {
268+ if version < ( 2 , 24 ) {
269+ return Ok ( None )
270+ }
271+ } else {
272+ return Ok ( None )
273+ }
274+ }
275+
276+ let mut p = Process { pid : 0 , status : None } ;
277+
278+ struct PosixSpawnFileActions ( libc:: posix_spawn_file_actions_t ) ;
279+
280+ impl Drop for PosixSpawnFileActions {
281+ fn drop ( & mut self ) {
282+ unsafe {
283+ libc:: posix_spawn_file_actions_destroy ( & mut self . 0 ) ;
284+ }
285+ }
286+ }
287+
288+ struct PosixSpawnattr ( libc:: posix_spawnattr_t ) ;
289+
290+ impl Drop for PosixSpawnattr {
291+ fn drop ( & mut self ) {
292+ unsafe {
293+ libc:: posix_spawnattr_destroy ( & mut self . 0 ) ;
294+ }
295+ }
296+ }
297+
298+ unsafe {
299+ let mut file_actions = PosixSpawnFileActions ( mem:: uninitialized ( ) ) ;
300+ let mut attrs = PosixSpawnattr ( mem:: uninitialized ( ) ) ;
301+
302+ libc:: posix_spawnattr_init ( & mut attrs. 0 ) ;
303+ libc:: posix_spawn_file_actions_init ( & mut file_actions. 0 ) ;
304+
305+ if let Some ( fd) = stdio. stdin . fd ( ) {
306+ cvt ( libc:: posix_spawn_file_actions_adddup2 ( & mut file_actions. 0 ,
307+ fd,
308+ libc:: STDIN_FILENO ) ) ?;
309+ }
310+ if let Some ( fd) = stdio. stdout . fd ( ) {
311+ cvt ( libc:: posix_spawn_file_actions_adddup2 ( & mut file_actions. 0 ,
312+ fd,
313+ libc:: STDOUT_FILENO ) ) ?;
314+ }
315+ if let Some ( fd) = stdio. stderr . fd ( ) {
316+ cvt ( libc:: posix_spawn_file_actions_adddup2 ( & mut file_actions. 0 ,
317+ fd,
318+ libc:: STDERR_FILENO ) ) ?;
319+ }
320+
321+ let mut set: libc:: sigset_t = mem:: uninitialized ( ) ;
322+ cvt ( libc:: sigemptyset ( & mut set) ) ?;
323+ cvt ( libc:: posix_spawnattr_setsigmask ( & mut attrs. 0 ,
324+ & set) ) ?;
325+ cvt ( libc:: sigaddset ( & mut set, libc:: SIGPIPE ) ) ?;
326+ cvt ( libc:: posix_spawnattr_setsigdefault ( & mut attrs. 0 ,
327+ & set) ) ?;
328+
329+ let flags = libc:: POSIX_SPAWN_SETSIGDEF |
330+ libc:: POSIX_SPAWN_SETSIGMASK ;
331+ cvt ( libc:: posix_spawnattr_setflags ( & mut attrs. 0 , flags as _ ) ) ?;
332+
333+ let envp = envp. map ( |c| c. as_ptr ( ) )
334+ . unwrap_or ( * sys:: os:: environ ( ) as * const _ ) ;
335+ let ret = libc:: posix_spawnp (
336+ & mut p. pid ,
337+ self . get_argv ( ) [ 0 ] ,
338+ & file_actions. 0 ,
339+ & attrs. 0 ,
340+ self . get_argv ( ) . as_ptr ( ) as * const _ ,
341+ envp as * const _ ,
342+ ) ;
343+ if ret == 0 {
344+ Ok ( Some ( p) )
345+ } else {
346+ Err ( io:: Error :: from_raw_os_error ( ret) )
347+ }
348+ }
349+ }
232350}
233351
234352////////////////////////////////////////////////////////////////////////////////
0 commit comments