10
10
11
11
use libc:: { pid_t, c_void, c_int} ;
12
12
use libc;
13
+ use std:: c_str:: CString ;
14
+ use std:: io;
13
15
use std:: mem;
14
16
use std:: os;
15
17
use std:: ptr;
16
- use std:: rt:: rtio;
17
18
use std:: rt:: rtio:: { ProcessConfig , IoResult , IoError } ;
18
- use std:: c_str :: CString ;
19
+ use std:: rt :: rtio ;
19
20
20
21
use super :: file;
21
22
use super :: util;
@@ -73,47 +74,43 @@ impl Process {
73
74
74
75
fn get_io ( io : rtio:: StdioContainer ,
75
76
ret : & mut Vec < Option < file:: FileDesc > > )
76
- -> ( Option < os :: Pipe > , c_int )
77
+ -> IoResult < Option < file :: FileDesc > >
77
78
{
78
79
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
+ }
81
85
rtio:: CreatePipe ( readable, _writable) => {
82
- let pipe = os :: pipe ( ) ;
86
+ let ( reader , writer ) = try! ( pipe ( ) ) ;
83
87
let ( theirs, ours) = if readable {
84
- ( pipe . input , pipe . out )
88
+ ( reader , writer )
85
89
} else {
86
- ( pipe . out , pipe . input )
90
+ ( writer , reader )
87
91
} ;
88
- ret. push ( Some ( file :: FileDesc :: new ( ours, true ) ) ) ;
89
- ( Some ( pipe ) , theirs)
92
+ ret. push ( Some ( ours) ) ;
93
+ Ok ( Some ( theirs) )
90
94
}
91
95
}
92
96
}
93
97
94
98
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) ) ) ;
106
103
107
104
match res {
108
105
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) )
117
114
}
118
115
Err ( e) => Err ( e)
119
116
}
@@ -194,6 +191,37 @@ impl Drop for Process {
194
191
}
195
192
}
196
193
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
+
197
225
#[ cfg( windows) ]
198
226
unsafe fn killpid ( pid : pid_t , signal : int ) -> IoResult < ( ) > {
199
227
let handle = libc:: OpenProcess ( libc:: PROCESS_TERMINATE |
@@ -246,7 +274,9 @@ struct SpawnProcessResult {
246
274
247
275
#[ cfg( windows) ]
248
276
fn 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 > )
250
280
-> IoResult < SpawnProcessResult > {
251
281
use libc:: types:: os:: arch:: extra:: { DWORD , HANDLE , STARTUPINFO } ;
252
282
use libc:: consts:: os:: extra:: {
@@ -283,47 +313,51 @@ fn spawn_process_os(cfg: ProcessConfig,
283
313
// Similarly to unix, we don't actually leave holes for the stdio file
284
314
// descriptors, but rather open up /dev/null equivalents. These
285
315
// 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
+ }
315
343
}
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
+ }
319
353
}
320
354
}
321
355
Ok ( ( ) )
322
356
} ;
323
357
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 ) ) ;
327
361
328
362
let cmd_str = make_command_line ( cfg. program , cfg. args ) ;
329
363
let mut pi = zeroed_process_information ( ) ;
@@ -464,7 +498,10 @@ fn make_command_line(prog: &CString, args: &[CString]) -> String {
464
498
}
465
499
466
500
#[ 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 > )
468
505
-> IoResult < SpawnProcessResult >
469
506
{
470
507
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
498
535
499
536
with_envp ( cfg. env , proc ( envp) {
500
537
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 ( ) ) ;
504
539
505
540
// We may use this in the child, so perform allocations before the
506
541
// fork
@@ -510,7 +545,7 @@ fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_i
510
545
511
546
let pid = fork ( ) ;
512
547
if pid < 0 {
513
- fail ! ( "failure in fork: {}" , os :: last_os_error ( ) ) ;
548
+ return Err ( super :: last_error ( ) )
514
549
} else if pid > 0 {
515
550
drop ( output) ;
516
551
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
586
621
// up /dev/null into that file descriptor. Otherwise, the first file
587
622
// descriptor opened up in the child would be numbered as one of the
588
623
// 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
+ }
599
642
} ;
600
643
src != -1 && retry ( || dup2 ( src, dst) ) != -1
601
644
} ;
0 commit comments