1010
1111use libc:: { pid_t, c_void, c_int} ;
1212use libc;
13+ use std:: c_str:: CString ;
14+ use std:: io;
1315use std:: mem;
1416use std:: os;
1517use std:: ptr;
16- use std:: rt:: rtio;
1718use std:: rt:: rtio:: { ProcessConfig , IoResult , IoError } ;
18- use std:: c_str :: CString ;
19+ use std:: rt :: rtio ;
1920
2021use super :: file;
2122use super :: util;
@@ -73,47 +74,43 @@ impl Process {
7374
7475 fn get_io ( io : rtio:: StdioContainer ,
7576 ret : & mut Vec < Option < file:: FileDesc > > )
76- -> ( Option < os :: Pipe > , c_int )
77+ -> IoResult < Option < file :: FileDesc > >
7778 {
7879 match io {
79- rtio:: Ignored => { ret. push ( None ) ; ( None , -1 ) }
80- rtio:: InheritFd ( fd) => { ret. push ( None ) ; ( None , fd) }
80+ rtio:: Ignored => { ret. push ( None ) ; Ok ( None ) }
81+ rtio:: InheritFd ( fd) => {
82+ ret. push ( None ) ;
83+ Ok ( Some ( file:: FileDesc :: new ( fd, true ) ) )
84+ }
8185 rtio:: CreatePipe ( readable, _writable) => {
82- let pipe = os :: pipe ( ) ;
86+ let ( reader , writer ) = try! ( pipe ( ) ) ;
8387 let ( theirs, ours) = if readable {
84- ( pipe . input , pipe . out )
88+ ( reader , writer )
8589 } else {
86- ( pipe . out , pipe . input )
90+ ( writer , reader )
8791 } ;
88- ret. push ( Some ( file :: FileDesc :: new ( ours, true ) ) ) ;
89- ( Some ( pipe ) , theirs)
92+ ret. push ( Some ( ours) ) ;
93+ Ok ( Some ( theirs) )
9094 }
9195 }
9296 }
9397
9498 let mut ret_io = Vec :: new ( ) ;
95- let ( in_pipe, in_fd) = get_io ( cfg. stdin , & mut ret_io) ;
96- let ( out_pipe, out_fd) = get_io ( cfg. stdout , & mut ret_io) ;
97- let ( err_pipe, err_fd) = get_io ( cfg. stderr , & mut ret_io) ;
98-
99- let res = spawn_process_os ( cfg, in_fd, out_fd, err_fd) ;
100-
101- unsafe {
102- for pipe in in_pipe. iter ( ) { let _ = libc:: close ( pipe. input ) ; }
103- for pipe in out_pipe. iter ( ) { let _ = libc:: close ( pipe. out ) ; }
104- for pipe in err_pipe. iter ( ) { let _ = libc:: close ( pipe. out ) ; }
105- }
99+ let res = spawn_process_os ( cfg,
100+ try!( get_io ( cfg. stdin , & mut ret_io) ) ,
101+ try!( get_io ( cfg. stdout , & mut ret_io) ) ,
102+ try!( get_io ( cfg. stderr , & mut ret_io) ) ) ;
106103
107104 match res {
108105 Ok ( res) => {
109- Ok ( ( Process {
110- pid : res. pid ,
111- handle : res. handle ,
112- exit_code : None ,
113- exit_signal : None ,
114- deadline : 0 ,
115- } ,
116- ret_io) )
106+ let p = Process {
107+ pid : res. pid ,
108+ handle : res. handle ,
109+ exit_code : None ,
110+ exit_signal : None ,
111+ deadline : 0 ,
112+ } ;
113+ Ok ( ( p , ret_io) )
117114 }
118115 Err ( e) => Err ( e)
119116 }
@@ -194,6 +191,37 @@ impl Drop for Process {
194191 }
195192}
196193
194+ fn pipe ( ) -> IoResult < ( file:: FileDesc , file:: FileDesc ) > {
195+ #[ cfg( unix) ] use ERROR = libc:: EMFILE ;
196+ #[ cfg( windows) ] use ERROR = libc:: WSAEMFILE ;
197+ struct Closer { fd : libc:: c_int }
198+
199+ let os:: Pipe { reader, writer } = match unsafe { os:: pipe ( ) } {
200+ Ok ( p) => p,
201+ Err ( io:: IoError { detail, .. } ) => return Err ( IoError {
202+ code : ERROR as uint ,
203+ extra : 0 ,
204+ detail : detail,
205+ } )
206+ } ;
207+ let mut reader = Closer { fd : reader } ;
208+ let mut writer = Closer { fd : writer } ;
209+
210+ let native_reader = file:: FileDesc :: new ( reader. fd , true ) ;
211+ reader. fd = -1 ;
212+ let native_writer = file:: FileDesc :: new ( writer. fd , true ) ;
213+ writer. fd = -1 ;
214+ return Ok ( ( native_reader, native_writer) ) ;
215+
216+ impl Drop for Closer {
217+ fn drop ( & mut self ) {
218+ if self . fd != -1 {
219+ let _ = unsafe { libc:: close ( self . fd ) } ;
220+ }
221+ }
222+ }
223+ }
224+
197225#[ cfg( windows) ]
198226unsafe fn killpid ( pid : pid_t , signal : int ) -> IoResult < ( ) > {
199227 let handle = libc:: OpenProcess ( libc:: PROCESS_TERMINATE |
@@ -246,7 +274,9 @@ struct SpawnProcessResult {
246274
247275#[ cfg( windows) ]
248276fn spawn_process_os ( cfg : ProcessConfig ,
249- in_fd : c_int , out_fd : c_int , err_fd : c_int )
277+ in_fd : Option < file:: FileDesc > ,
278+ out_fd : Option < file:: FileDesc > ,
279+ err_fd : Option < file:: FileDesc > )
250280 -> IoResult < SpawnProcessResult > {
251281 use libc:: types:: os:: arch:: extra:: { DWORD , HANDLE , STARTUPINFO } ;
252282 use libc:: consts:: os:: extra:: {
@@ -283,47 +313,51 @@ fn spawn_process_os(cfg: ProcessConfig,
283313 // Similarly to unix, we don't actually leave holes for the stdio file
284314 // descriptors, but rather open up /dev/null equivalents. These
285315 // equivalents are drawn from libuv's windows process spawning.
286- let set_fd = |fd : c_int , slot : & mut HANDLE , is_stdin : bool | {
287- if fd == -1 {
288- let access = if is_stdin {
289- libc:: FILE_GENERIC_READ
290- } else {
291- libc:: FILE_GENERIC_WRITE | libc:: FILE_READ_ATTRIBUTES
292- } ;
293- let size = mem:: size_of :: < libc:: SECURITY_ATTRIBUTES > ( ) ;
294- let mut sa = libc:: SECURITY_ATTRIBUTES {
295- nLength : size as libc:: DWORD ,
296- lpSecurityDescriptor : ptr:: mut_null ( ) ,
297- bInheritHandle : 1 ,
298- } ;
299- let filename = "NUL" . to_utf16 ( ) . append_one ( 0 ) ;
300- * slot = libc:: CreateFileW ( filename. as_ptr ( ) ,
301- access,
302- libc:: FILE_SHARE_READ |
303- libc:: FILE_SHARE_WRITE ,
304- & mut sa,
305- libc:: OPEN_EXISTING ,
306- 0 ,
307- ptr:: mut_null ( ) ) ;
308- if * slot == INVALID_HANDLE_VALUE as libc:: HANDLE {
309- return Err ( super :: last_error ( ) )
310- }
311- } else {
312- let orig = get_osfhandle ( fd) as HANDLE ;
313- if orig == INVALID_HANDLE_VALUE as HANDLE {
314- return Err ( super :: last_error ( ) )
316+ let set_fd = |fd : & Option < file:: FileDesc > , slot : & mut HANDLE ,
317+ is_stdin : bool | {
318+ match * fd {
319+ None => {
320+ let access = if is_stdin {
321+ libc:: FILE_GENERIC_READ
322+ } else {
323+ libc:: FILE_GENERIC_WRITE | libc:: FILE_READ_ATTRIBUTES
324+ } ;
325+ let size = mem:: size_of :: < libc:: SECURITY_ATTRIBUTES > ( ) ;
326+ let mut sa = libc:: SECURITY_ATTRIBUTES {
327+ nLength : size as libc:: DWORD ,
328+ lpSecurityDescriptor : ptr:: mut_null ( ) ,
329+ bInheritHandle : 1 ,
330+ } ;
331+ let filename = "NUL" . to_utf16 ( ) . append_one ( 0 ) ;
332+ * slot = libc:: CreateFileW ( filename. as_ptr ( ) ,
333+ access,
334+ libc:: FILE_SHARE_READ |
335+ libc:: FILE_SHARE_WRITE ,
336+ & mut sa,
337+ libc:: OPEN_EXISTING ,
338+ 0 ,
339+ ptr:: mut_null ( ) ) ;
340+ if * slot == INVALID_HANDLE_VALUE as libc:: HANDLE {
341+ return Err ( super :: last_error ( ) )
342+ }
315343 }
316- if DuplicateHandle ( cur_proc, orig, cur_proc, slot,
317- 0 , TRUE , DUPLICATE_SAME_ACCESS ) == FALSE {
318- return Err ( super :: last_error ( ) )
344+ Some ( ref fd) => {
345+ let orig = get_osfhandle ( fd. fd ( ) ) as HANDLE ;
346+ if orig == INVALID_HANDLE_VALUE as HANDLE {
347+ return Err ( super :: last_error ( ) )
348+ }
349+ if DuplicateHandle ( cur_proc, orig, cur_proc, slot,
350+ 0 , TRUE , DUPLICATE_SAME_ACCESS ) == FALSE {
351+ return Err ( super :: last_error ( ) )
352+ }
319353 }
320354 }
321355 Ok ( ( ) )
322356 } ;
323357
324- try!( set_fd ( in_fd, & mut si. hStdInput , true ) ) ;
325- try!( set_fd ( out_fd, & mut si. hStdOutput , false ) ) ;
326- try!( set_fd ( err_fd, & mut si. hStdError , false ) ) ;
358+ try!( set_fd ( & in_fd, & mut si. hStdInput , true ) ) ;
359+ try!( set_fd ( & out_fd, & mut si. hStdOutput , false ) ) ;
360+ try!( set_fd ( & err_fd, & mut si. hStdError , false ) ) ;
327361
328362 let cmd_str = make_command_line ( cfg. program , cfg. args ) ;
329363 let mut pi = zeroed_process_information ( ) ;
@@ -464,7 +498,10 @@ fn make_command_line(prog: &CString, args: &[CString]) -> String {
464498}
465499
466500#[ cfg( unix) ]
467- fn spawn_process_os ( cfg : ProcessConfig , in_fd : c_int , out_fd : c_int , err_fd : c_int )
501+ fn spawn_process_os ( cfg : ProcessConfig ,
502+ in_fd : Option < file:: FileDesc > ,
503+ out_fd : Option < file:: FileDesc > ,
504+ err_fd : Option < file:: FileDesc > )
468505 -> IoResult < SpawnProcessResult >
469506{
470507 use libc:: funcs:: posix88:: unistd:: { fork, dup2, close, chdir, execvp} ;
@@ -498,9 +535,7 @@ fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_i
498535
499536 with_envp ( cfg. env , proc ( envp) {
500537 with_argv ( cfg. program , cfg. args , proc ( argv) unsafe {
501- let pipe = os:: pipe ( ) ;
502- let mut input = file:: FileDesc :: new ( pipe. input , true ) ;
503- let mut output = file:: FileDesc :: new ( pipe. out , true ) ;
538+ let ( mut input, mut output) = try!( pipe ( ) ) ;
504539
505540 // We may use this in the child, so perform allocations before the
506541 // fork
@@ -510,7 +545,7 @@ fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_i
510545
511546 let pid = fork ( ) ;
512547 if pid < 0 {
513- fail ! ( "failure in fork: {}" , os :: last_os_error ( ) ) ;
548+ return Err ( super :: last_error ( ) )
514549 } else if pid > 0 {
515550 drop ( output) ;
516551 let mut bytes = [ 0 , ..4 ] ;
@@ -586,16 +621,24 @@ fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_i
586621 // up /dev/null into that file descriptor. Otherwise, the first file
587622 // descriptor opened up in the child would be numbered as one of the
588623 // stdio file descriptors, which is likely to wreak havoc.
589- let setup = |src : c_int , dst : c_int | {
590- let src = if src == -1 {
591- let flags = if dst == libc:: STDIN_FILENO {
592- libc:: O_RDONLY
593- } else {
594- libc:: O_RDWR
595- } ;
596- devnull. with_ref ( |p| libc:: open ( p, flags, 0 ) )
597- } else {
598- src
624+ let setup = |src : Option < file:: FileDesc > , dst : c_int | {
625+ let src = match src {
626+ None => {
627+ let flags = if dst == libc:: STDIN_FILENO {
628+ libc:: O_RDONLY
629+ } else {
630+ libc:: O_RDWR
631+ } ;
632+ devnull. with_ref ( |p| libc:: open ( p, flags, 0 ) )
633+ }
634+ Some ( obj) => {
635+ let fd = obj. fd ( ) ;
636+ // Leak the memory and the file descriptor. We're in the
637+ // child now an all our resources are going to be
638+ // cleaned up very soon
639+ mem:: forget ( obj) ;
640+ fd
641+ }
599642 } ;
600643 src != -1 && retry ( || dup2 ( src, dst) ) != -1
601644 } ;
0 commit comments