@@ -34,6 +34,11 @@ impl Command {
34
34
}
35
35
36
36
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
+
37
42
let ( input, output) = sys:: pipe:: anon_pipe ( ) ?;
38
43
39
44
let pid = unsafe {
@@ -229,6 +234,119 @@ impl Command {
229
234
libc:: execvp ( self . get_argv ( ) [ 0 ] , self . get_argv ( ) . as_ptr ( ) ) ;
230
235
io:: Error :: last_os_error ( )
231
236
}
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
+ }
232
350
}
233
351
234
352
////////////////////////////////////////////////////////////////////////////////
0 commit comments