]> git.lizzy.rs Git - rust.git/blob - src/libnative/io/process.rs
auto merge of #17654 : gereeter/rust/no-unnecessary-cell, r=alexcrichton
[rust.git] / src / libnative / io / process.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use libc::{pid_t, c_void, c_int};
12 use libc;
13 use std::c_str::CString;
14 use std::io;
15 use std::mem;
16 use std::os;
17 use std::ptr;
18 use std::rt::rtio::{ProcessConfig, IoResult, IoError};
19 use std::rt::rtio;
20
21 use super::file;
22 use super::util;
23
24 #[cfg(windows)] use std::io::fs::PathExtensions;
25 #[cfg(windows)] use std::string::String;
26 #[cfg(unix)] use super::c;
27 #[cfg(unix)] use super::retry;
28 #[cfg(unix)] use io::helper_thread::Helper;
29
30 #[cfg(unix)]
31 helper_init!(static mut HELPER: Helper<Req>)
32
33 /**
34  * A value representing a child process.
35  *
36  * The lifetime of this value is linked to the lifetime of the actual
37  * process - the Process destructor calls self.finish() which waits
38  * for the process to terminate.
39  */
40 pub struct Process {
41     /// The unique id of the process (this should never be negative).
42     pid: pid_t,
43
44     /// A handle to the process - on unix this will always be NULL, but on
45     /// windows it will be a HANDLE to the process, which will prevent the
46     /// pid being re-used until the handle is closed.
47     handle: *mut (),
48
49     /// None until finish() is called.
50     exit_code: Option<rtio::ProcessExit>,
51
52     /// Manually delivered signal
53     exit_signal: Option<int>,
54
55     /// Deadline after which wait() will return
56     deadline: u64,
57 }
58
59 #[cfg(unix)]
60 enum Req {
61     NewChild(libc::pid_t, Sender<rtio::ProcessExit>, u64),
62 }
63
64 impl Process {
65     /// Creates a new process using native process-spawning abilities provided
66     /// by the OS. Operations on this process will be blocking instead of using
67     /// the runtime for sleeping just this current task.
68     pub fn spawn(cfg: ProcessConfig)
69         -> IoResult<(Process, Vec<Option<file::FileDesc>>)>
70     {
71         // right now we only handle stdin/stdout/stderr.
72         if cfg.extra_io.len() > 0 {
73             return Err(super::unimpl());
74         }
75
76         fn get_io(io: rtio::StdioContainer,
77                   ret: &mut Vec<Option<file::FileDesc>>)
78             -> IoResult<Option<file::FileDesc>>
79         {
80             match io {
81                 rtio::Ignored => { ret.push(None); Ok(None) }
82                 rtio::InheritFd(fd) => {
83                     ret.push(None);
84                     Ok(Some(file::FileDesc::new(fd, false)))
85                 }
86                 rtio::CreatePipe(readable, _writable) => {
87                     let (reader, writer) = try!(pipe());
88                     let (theirs, ours) = if readable {
89                         (reader, writer)
90                     } else {
91                         (writer, reader)
92                     };
93                     ret.push(Some(ours));
94                     Ok(Some(theirs))
95                 }
96             }
97         }
98
99         let mut ret_io = Vec::new();
100         let res = spawn_process_os(cfg,
101                                    try!(get_io(cfg.stdin, &mut ret_io)),
102                                    try!(get_io(cfg.stdout, &mut ret_io)),
103                                    try!(get_io(cfg.stderr, &mut ret_io)));
104
105         match res {
106             Ok(res) => {
107                 let p = Process {
108                     pid: res.pid,
109                     handle: res.handle,
110                     exit_code: None,
111                     exit_signal: None,
112                     deadline: 0,
113                 };
114                 Ok((p, ret_io))
115             }
116             Err(e) => Err(e)
117         }
118     }
119
120     pub fn kill(pid: libc::pid_t, signum: int) -> IoResult<()> {
121         unsafe { killpid(pid, signum) }
122     }
123 }
124
125 impl rtio::RtioProcess for Process {
126     fn id(&self) -> pid_t { self.pid }
127
128     fn set_timeout(&mut self, timeout: Option<u64>) {
129         self.deadline = timeout.map(|i| i + ::io::timer::now()).unwrap_or(0);
130     }
131
132     fn wait(&mut self) -> IoResult<rtio::ProcessExit> {
133         match self.exit_code {
134             Some(code) => Ok(code),
135             None => {
136                 let code = try!(waitpid(self.pid, self.deadline));
137                 // On windows, waitpid will never return a signal. If a signal
138                 // was successfully delivered to the process, however, we can
139                 // consider it as having died via a signal.
140                 let code = match self.exit_signal {
141                     None => code,
142                     Some(signal) if cfg!(windows) => rtio::ExitSignal(signal),
143                     Some(..) => code,
144                 };
145                 self.exit_code = Some(code);
146                 Ok(code)
147             }
148         }
149     }
150
151     fn kill(&mut self, signum: int) -> IoResult<()> {
152         #[cfg(unix)] use libc::EINVAL as ERROR;
153         #[cfg(windows)] use libc::ERROR_NOTHING_TO_TERMINATE as ERROR;
154
155         // On Linux (and possibly other unices), a process that has exited will
156         // continue to accept signals because it is "defunct". The delivery of
157         // signals will only fail once the child has been reaped. For this
158         // reason, if the process hasn't exited yet, then we attempt to collect
159         // their status with WNOHANG.
160         if self.exit_code.is_none() {
161             match waitpid_nowait(self.pid) {
162                 Some(code) => { self.exit_code = Some(code); }
163                 None => {}
164             }
165         }
166
167         // if the process has finished, and therefore had waitpid called,
168         // and we kill it, then on unix we might ending up killing a
169         // newer process that happens to have the same (re-used) id
170         match self.exit_code {
171             Some(..) => return Err(IoError {
172                 code: ERROR as uint,
173                 extra: 0,
174                 detail: Some("can't kill an exited process".to_string()),
175             }),
176             None => {}
177         }
178
179         // A successfully delivered signal that isn't 0 (just a poll for being
180         // alive) is recorded for windows (see wait())
181         match unsafe { killpid(self.pid, signum) } {
182             Ok(()) if signum == 0 => Ok(()),
183             Ok(()) => { self.exit_signal = Some(signum); Ok(()) }
184             Err(e) => Err(e),
185         }
186     }
187 }
188
189 impl Drop for Process {
190     fn drop(&mut self) {
191         free_handle(self.handle);
192     }
193 }
194
195 pub fn pipe() -> IoResult<(file::FileDesc, file::FileDesc)> {
196     #[cfg(unix)] use libc::EMFILE as ERROR;
197     #[cfg(windows)] use libc::WSAEMFILE as ERROR;
198     struct Closer { fd: libc::c_int }
199
200     let os::Pipe { reader, writer } = match unsafe { os::pipe() } {
201         Ok(p) => p,
202         Err(io::IoError { detail, .. }) => return Err(IoError {
203             code: ERROR as uint,
204             extra: 0,
205             detail: detail,
206         })
207     };
208     let mut reader = Closer { fd: reader };
209     let mut writer = Closer { fd: writer };
210
211     let native_reader = file::FileDesc::new(reader.fd, true);
212     reader.fd = -1;
213     let native_writer = file::FileDesc::new(writer.fd, true);
214     writer.fd = -1;
215     return Ok((native_reader, native_writer));
216
217     impl Drop for Closer {
218         fn drop(&mut self) {
219             if self.fd != -1 {
220                 let _ = unsafe { libc::close(self.fd) };
221             }
222         }
223     }
224 }
225
226 #[cfg(windows)]
227 unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> {
228     let handle = libc::OpenProcess(libc::PROCESS_TERMINATE |
229                                    libc::PROCESS_QUERY_INFORMATION,
230                                    libc::FALSE, pid as libc::DWORD);
231     if handle.is_null() {
232         return Err(super::last_error())
233     }
234     let ret = match signal {
235         // test for existence on signal 0
236         0 => {
237             let mut status = 0;
238             let ret = libc::GetExitCodeProcess(handle, &mut status);
239             if ret == 0 {
240                 Err(super::last_error())
241             } else if status != libc::STILL_ACTIVE {
242                 Err(IoError {
243                     code: libc::ERROR_NOTHING_TO_TERMINATE as uint,
244                     extra: 0,
245                     detail: None,
246                 })
247             } else {
248                 Ok(())
249             }
250         }
251         15 | 9 => { // sigterm or sigkill
252             let ret = libc::TerminateProcess(handle, 1);
253             super::mkerr_winbool(ret)
254         }
255         _ => Err(IoError {
256             code: libc::ERROR_CALL_NOT_IMPLEMENTED as uint,
257             extra: 0,
258             detail: Some("unsupported signal on windows".to_string()),
259         })
260     };
261     let _ = libc::CloseHandle(handle);
262     return ret;
263 }
264
265 #[cfg(not(windows))]
266 unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> {
267     let r = libc::funcs::posix88::signal::kill(pid, signal as c_int);
268     super::mkerr_libc(r)
269 }
270
271 struct SpawnProcessResult {
272     pid: pid_t,
273     handle: *mut (),
274 }
275
276 #[cfg(windows)]
277 fn spawn_process_os(cfg: ProcessConfig,
278                     in_fd: Option<file::FileDesc>,
279                     out_fd: Option<file::FileDesc>,
280                     err_fd: Option<file::FileDesc>)
281                  -> IoResult<SpawnProcessResult> {
282     use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
283     use libc::consts::os::extra::{
284         TRUE, FALSE,
285         STARTF_USESTDHANDLES,
286         INVALID_HANDLE_VALUE,
287         DUPLICATE_SAME_ACCESS
288     };
289     use libc::funcs::extra::kernel32::{
290         GetCurrentProcess,
291         DuplicateHandle,
292         CloseHandle,
293         CreateProcessW
294     };
295     use libc::funcs::extra::msvcrt::get_osfhandle;
296
297     use std::mem;
298     use std::iter::Iterator;
299     use std::str::StrSlice;
300
301     if cfg.gid.is_some() || cfg.uid.is_some() {
302         return Err(IoError {
303             code: libc::ERROR_CALL_NOT_IMPLEMENTED as uint,
304             extra: 0,
305             detail: Some("unsupported gid/uid requested on windows".to_string()),
306         })
307     }
308
309     // To have the spawning semantics of unix/windows stay the same, we need to
310     // read the *child's* PATH if one is provided. See #15149 for more details.
311     let program = cfg.env.and_then(|env| {
312         for &(ref key, ref v) in env.iter() {
313             if b"PATH" != key.as_bytes_no_nul() { continue }
314
315             // Split the value and test each path to see if the program exists.
316             for path in os::split_paths(v.as_bytes_no_nul()).into_iter() {
317                 let path = path.join(cfg.program.as_bytes_no_nul())
318                                .with_extension(os::consts::EXE_EXTENSION);
319                 if path.exists() {
320                     return Some(path.to_c_str())
321                 }
322             }
323             break
324         }
325         None
326     });
327
328     unsafe {
329         let mut si = zeroed_startupinfo();
330         si.cb = mem::size_of::<STARTUPINFO>() as DWORD;
331         si.dwFlags = STARTF_USESTDHANDLES;
332
333         let cur_proc = GetCurrentProcess();
334
335         // Similarly to unix, we don't actually leave holes for the stdio file
336         // descriptors, but rather open up /dev/null equivalents. These
337         // equivalents are drawn from libuv's windows process spawning.
338         let set_fd = |fd: &Option<file::FileDesc>, slot: &mut HANDLE,
339                       is_stdin: bool| {
340             match *fd {
341                 None => {
342                     let access = if is_stdin {
343                         libc::FILE_GENERIC_READ
344                     } else {
345                         libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES
346                     };
347                     let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>();
348                     let mut sa = libc::SECURITY_ATTRIBUTES {
349                         nLength: size as libc::DWORD,
350                         lpSecurityDescriptor: ptr::null_mut(),
351                         bInheritHandle: 1,
352                     };
353                     let filename: Vec<u16> = "NUL".utf16_units().collect();
354                     let filename = filename.append_one(0);
355                     *slot = libc::CreateFileW(filename.as_ptr(),
356                                               access,
357                                               libc::FILE_SHARE_READ |
358                                                   libc::FILE_SHARE_WRITE,
359                                               &mut sa,
360                                               libc::OPEN_EXISTING,
361                                               0,
362                                               ptr::null_mut());
363                     if *slot == INVALID_HANDLE_VALUE {
364                         return Err(super::last_error())
365                     }
366                 }
367                 Some(ref fd) => {
368                     let orig = get_osfhandle(fd.fd()) as HANDLE;
369                     if orig == INVALID_HANDLE_VALUE {
370                         return Err(super::last_error())
371                     }
372                     if DuplicateHandle(cur_proc, orig, cur_proc, slot,
373                                        0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
374                         return Err(super::last_error())
375                     }
376                 }
377             }
378             Ok(())
379         };
380
381         try!(set_fd(&in_fd, &mut si.hStdInput, true));
382         try!(set_fd(&out_fd, &mut si.hStdOutput, false));
383         try!(set_fd(&err_fd, &mut si.hStdError, false));
384
385         let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program),
386                                         cfg.args);
387         let mut pi = zeroed_process_information();
388         let mut create_err = None;
389
390         // stolen from the libuv code.
391         let mut flags = libc::CREATE_UNICODE_ENVIRONMENT;
392         if cfg.detach {
393             flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP;
394         }
395
396         with_envp(cfg.env, |envp| {
397             with_dirp(cfg.cwd, |dirp| {
398                 let mut cmd_str: Vec<u16> = cmd_str.as_slice().utf16_units().collect();
399                 cmd_str = cmd_str.append_one(0);
400                 let created = CreateProcessW(ptr::null(),
401                                              cmd_str.as_mut_ptr(),
402                                              ptr::null_mut(),
403                                              ptr::null_mut(),
404                                              TRUE,
405                                              flags, envp, dirp,
406                                              &mut si, &mut pi);
407                 if created == FALSE {
408                     create_err = Some(super::last_error());
409                 }
410             })
411         });
412
413         assert!(CloseHandle(si.hStdInput) != 0);
414         assert!(CloseHandle(si.hStdOutput) != 0);
415         assert!(CloseHandle(si.hStdError) != 0);
416
417         match create_err {
418             Some(err) => return Err(err),
419             None => {}
420         }
421
422         // We close the thread handle because we don't care about keeping the
423         // thread id valid, and we aren't keeping the thread handle around to be
424         // able to close it later. We don't close the process handle however
425         // because std::we want the process id to stay valid at least until the
426         // calling code closes the process handle.
427         assert!(CloseHandle(pi.hThread) != 0);
428
429         Ok(SpawnProcessResult {
430             pid: pi.dwProcessId as pid_t,
431             handle: pi.hProcess as *mut ()
432         })
433     }
434 }
435
436 #[cfg(windows)]
437 fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
438     libc::types::os::arch::extra::STARTUPINFO {
439         cb: 0,
440         lpReserved: ptr::null_mut(),
441         lpDesktop: ptr::null_mut(),
442         lpTitle: ptr::null_mut(),
443         dwX: 0,
444         dwY: 0,
445         dwXSize: 0,
446         dwYSize: 0,
447         dwXCountChars: 0,
448         dwYCountCharts: 0,
449         dwFillAttribute: 0,
450         dwFlags: 0,
451         wShowWindow: 0,
452         cbReserved2: 0,
453         lpReserved2: ptr::null_mut(),
454         hStdInput: libc::INVALID_HANDLE_VALUE,
455         hStdOutput: libc::INVALID_HANDLE_VALUE,
456         hStdError: libc::INVALID_HANDLE_VALUE,
457     }
458 }
459
460 #[cfg(windows)]
461 fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
462     libc::types::os::arch::extra::PROCESS_INFORMATION {
463         hProcess: ptr::null_mut(),
464         hThread: ptr::null_mut(),
465         dwProcessId: 0,
466         dwThreadId: 0
467     }
468 }
469
470 #[cfg(windows)]
471 fn make_command_line(prog: &CString, args: &[CString]) -> String {
472     let mut cmd = String::new();
473     append_arg(&mut cmd, prog.as_str()
474                              .expect("expected program name to be utf-8 encoded"));
475     for arg in args.iter() {
476         cmd.push_char(' ');
477         append_arg(&mut cmd, arg.as_str()
478                                 .expect("expected argument to be utf-8 encoded"));
479     }
480     return cmd;
481
482     fn append_arg(cmd: &mut String, arg: &str) {
483         // If an argument has 0 characters then we need to quote it to ensure
484         // that it actually gets passed through on the command line or otherwise
485         // it will be dropped entirely when parsed on the other end.
486         let quote = arg.chars().any(|c| c == ' ' || c == '\t') || arg.len() == 0;
487         if quote {
488             cmd.push_char('"');
489         }
490         let argvec: Vec<char> = arg.chars().collect();
491         for i in range(0u, argvec.len()) {
492             append_char_at(cmd, &argvec, i);
493         }
494         if quote {
495             cmd.push_char('"');
496         }
497     }
498
499     fn append_char_at(cmd: &mut String, arg: &Vec<char>, i: uint) {
500         match *arg.get(i) {
501             '"' => {
502                 // Escape quotes.
503                 cmd.push_str("\\\"");
504             }
505             '\\' => {
506                 if backslash_run_ends_in_quote(arg, i) {
507                     // Double all backslashes that are in runs before quotes.
508                     cmd.push_str("\\\\");
509                 } else {
510                     // Pass other backslashes through unescaped.
511                     cmd.push_char('\\');
512                 }
513             }
514             c => {
515                 cmd.push_char(c);
516             }
517         }
518     }
519
520     fn backslash_run_ends_in_quote(s: &Vec<char>, mut i: uint) -> bool {
521         while i < s.len() && *s.get(i) == '\\' {
522             i += 1;
523         }
524         return i < s.len() && *s.get(i) == '"';
525     }
526 }
527
528 #[cfg(unix)]
529 fn spawn_process_os(cfg: ProcessConfig,
530                     in_fd: Option<file::FileDesc>,
531                     out_fd: Option<file::FileDesc>,
532                     err_fd: Option<file::FileDesc>)
533                 -> IoResult<SpawnProcessResult>
534 {
535     use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
536     use libc::funcs::bsd44::getdtablesize;
537     use io::c;
538
539     mod rustrt {
540         extern {
541             pub fn rust_unset_sigprocmask();
542         }
543     }
544
545     #[cfg(target_os = "macos")]
546     unsafe fn set_environ(envp: *const c_void) {
547         extern { fn _NSGetEnviron() -> *mut *const c_void; }
548
549         *_NSGetEnviron() = envp;
550     }
551     #[cfg(not(target_os = "macos"))]
552     unsafe fn set_environ(envp: *const c_void) {
553         extern { static mut environ: *const c_void; }
554         environ = envp;
555     }
556
557     unsafe fn set_cloexec(fd: c_int) {
558         let ret = c::ioctl(fd, c::FIOCLEX);
559         assert_eq!(ret, 0);
560     }
561
562     let dirp = cfg.cwd.map(|c| c.as_ptr()).unwrap_or(ptr::null());
563
564     let cfg = unsafe {
565         mem::transmute::<ProcessConfig,ProcessConfig<'static>>(cfg)
566     };
567
568     with_envp(cfg.env, proc(envp) {
569         with_argv(cfg.program, cfg.args, proc(argv) unsafe {
570             let (mut input, mut output) = try!(pipe());
571
572             // We may use this in the child, so perform allocations before the
573             // fork
574             let devnull = "/dev/null".to_c_str();
575
576             set_cloexec(output.fd());
577
578             let pid = fork();
579             if pid < 0 {
580                 return Err(super::last_error())
581             } else if pid > 0 {
582                 drop(output);
583                 let mut bytes = [0, ..4];
584                 return match input.inner_read(bytes) {
585                     Ok(4) => {
586                         let errno = (bytes[0] << 24) as i32 |
587                                     (bytes[1] << 16) as i32 |
588                                     (bytes[2] <<  8) as i32 |
589                                     (bytes[3] <<  0) as i32;
590                         Err(IoError {
591                             code: errno as uint,
592                             detail: None,
593                             extra: 0,
594                         })
595                     }
596                     Err(..) => {
597                         Ok(SpawnProcessResult {
598                             pid: pid,
599                             handle: ptr::null_mut()
600                         })
601                     }
602                     Ok(..) => fail!("short read on the cloexec pipe"),
603                 };
604             }
605             // And at this point we've reached a special time in the life of the
606             // child. The child must now be considered hamstrung and unable to
607             // do anything other than syscalls really. Consider the following
608             // scenario:
609             //
610             //      1. Thread A of process 1 grabs the malloc() mutex
611             //      2. Thread B of process 1 forks(), creating thread C
612             //      3. Thread C of process 2 then attempts to malloc()
613             //      4. The memory of process 2 is the same as the memory of
614             //         process 1, so the mutex is locked.
615             //
616             // This situation looks a lot like deadlock, right? It turns out
617             // that this is what pthread_atfork() takes care of, which is
618             // presumably implemented across platforms. The first thing that
619             // threads to *before* forking is to do things like grab the malloc
620             // mutex, and then after the fork they unlock it.
621             //
622             // Despite this information, libnative's spawn has been witnessed to
623             // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but
624             // all collected backtraces point at malloc/free traffic in the
625             // child spawned process.
626             //
627             // For this reason, the block of code below should contain 0
628             // invocations of either malloc of free (or their related friends).
629             //
630             // As an example of not having malloc/free traffic, we don't close
631             // this file descriptor by dropping the FileDesc (which contains an
632             // allocation). Instead we just close it manually. This will never
633             // have the drop glue anyway because this code never returns (the
634             // child will either exec() or invoke libc::exit)
635             let _ = libc::close(input.fd());
636
637             fn fail(output: &mut file::FileDesc) -> ! {
638                 let errno = os::errno();
639                 let bytes = [
640                     (errno << 24) as u8,
641                     (errno << 16) as u8,
642                     (errno <<  8) as u8,
643                     (errno <<  0) as u8,
644                 ];
645                 assert!(output.inner_write(bytes).is_ok());
646                 unsafe { libc::_exit(1) }
647             }
648
649             rustrt::rust_unset_sigprocmask();
650
651             // If a stdio file descriptor is set to be ignored (via a -1 file
652             // descriptor), then we don't actually close it, but rather open
653             // up /dev/null into that file descriptor. Otherwise, the first file
654             // descriptor opened up in the child would be numbered as one of the
655             // stdio file descriptors, which is likely to wreak havoc.
656             let setup = |src: Option<file::FileDesc>, dst: c_int| {
657                 let src = match src {
658                     None => {
659                         let flags = if dst == libc::STDIN_FILENO {
660                             libc::O_RDONLY
661                         } else {
662                             libc::O_RDWR
663                         };
664                         libc::open(devnull.as_ptr(), flags, 0)
665                     }
666                     Some(obj) => {
667                         let fd = obj.fd();
668                         // Leak the memory and the file descriptor. We're in the
669                         // child now an all our resources are going to be
670                         // cleaned up very soon
671                         mem::forget(obj);
672                         fd
673                     }
674                 };
675                 src != -1 && retry(|| dup2(src, dst)) != -1
676             };
677
678             if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) }
679             if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) }
680             if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) }
681
682             // close all other fds
683             for fd in range(3, getdtablesize()).rev() {
684                 if fd != output.fd() {
685                     let _ = close(fd as c_int);
686                 }
687             }
688
689             match cfg.gid {
690                 Some(u) => {
691                     if libc::setgid(u as libc::gid_t) != 0 {
692                         fail(&mut output);
693                     }
694                 }
695                 None => {}
696             }
697             match cfg.uid {
698                 Some(u) => {
699                     // When dropping privileges from root, the `setgroups` call
700                     // will remove any extraneous groups. If we don't call this,
701                     // then even though our uid has dropped, we may still have
702                     // groups that enable us to do super-user things. This will
703                     // fail if we aren't root, so don't bother checking the
704                     // return value, this is just done as an optimistic
705                     // privilege dropping function.
706                     extern {
707                         fn setgroups(ngroups: libc::c_int,
708                                      ptr: *const libc::c_void) -> libc::c_int;
709                     }
710                     let _ = setgroups(0, 0 as *const libc::c_void);
711
712                     if libc::setuid(u as libc::uid_t) != 0 {
713                         fail(&mut output);
714                     }
715                 }
716                 None => {}
717             }
718             if cfg.detach {
719                 // Don't check the error of setsid because it fails if we're the
720                 // process leader already. We just forked so it shouldn't return
721                 // error, but ignore it anyway.
722                 let _ = libc::setsid();
723             }
724             if !dirp.is_null() && chdir(dirp) == -1 {
725                 fail(&mut output);
726             }
727             if !envp.is_null() {
728                 set_environ(envp);
729             }
730             let _ = execvp(*argv, argv as *mut _);
731             fail(&mut output);
732         })
733     })
734 }
735
736 #[cfg(unix)]
737 fn with_argv<T>(prog: &CString, args: &[CString],
738                 cb: proc(*const *const libc::c_char) -> T) -> T {
739     let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1);
740
741     // Convert the CStrings into an array of pointers. Note: the
742     // lifetime of the various CStrings involved is guaranteed to be
743     // larger than the lifetime of our invocation of cb, but this is
744     // technically unsafe as the callback could leak these pointers
745     // out of our scope.
746     ptrs.push(prog.as_ptr());
747     ptrs.extend(args.iter().map(|tmp| tmp.as_ptr()));
748
749     // Add a terminating null pointer (required by libc).
750     ptrs.push(ptr::null());
751
752     cb(ptrs.as_ptr())
753 }
754
755 #[cfg(unix)]
756 fn with_envp<T>(env: Option<&[(&CString, &CString)]>,
757                 cb: proc(*const c_void) -> T) -> T {
758     // On posixy systems we can pass a char** for envp, which is a
759     // null-terminated array of "k=v\0" strings. Since we must create
760     // these strings locally, yet expose a raw pointer to them, we
761     // create a temporary vector to own the CStrings that outlives the
762     // call to cb.
763     match env {
764         Some(env) => {
765             let mut tmps = Vec::with_capacity(env.len());
766
767             for pair in env.iter() {
768                 let mut kv = Vec::new();
769                 kv.push_all(pair.ref0().as_bytes_no_nul());
770                 kv.push('=' as u8);
771                 kv.push_all(pair.ref1().as_bytes()); // includes terminal \0
772                 tmps.push(kv);
773             }
774
775             // As with `with_argv`, this is unsafe, since cb could leak the pointers.
776             let mut ptrs: Vec<*const libc::c_char> =
777                 tmps.iter()
778                     .map(|tmp| tmp.as_ptr() as *const libc::c_char)
779                     .collect();
780             ptrs.push(ptr::null());
781
782             cb(ptrs.as_ptr() as *const c_void)
783         }
784         _ => cb(ptr::null())
785     }
786 }
787
788 #[cfg(windows)]
789 fn with_envp<T>(env: Option<&[(&CString, &CString)]>, cb: |*mut c_void| -> T) -> T {
790     // On Windows we pass an "environment block" which is not a char**, but
791     // rather a concatenation of null-terminated k=v\0 sequences, with a final
792     // \0 to terminate.
793     match env {
794         Some(env) => {
795             let mut blk = Vec::new();
796
797             for pair in env.iter() {
798                 let kv = format!("{}={}",
799                                  pair.ref0().as_str().unwrap(),
800                                  pair.ref1().as_str().unwrap());
801                 blk.extend(kv.as_slice().utf16_units());
802                 blk.push(0);
803             }
804
805             blk.push(0);
806
807             cb(blk.as_mut_ptr() as *mut c_void)
808         }
809         _ => cb(ptr::null_mut())
810     }
811 }
812
813 #[cfg(windows)]
814 fn with_dirp<T>(d: Option<&CString>, cb: |*const u16| -> T) -> T {
815     match d {
816       Some(dir) => {
817           let dir_str = dir.as_str()
818                            .expect("expected workingdirectory to be utf-8 encoded");
819           let dir_str: Vec<u16> = dir_str.utf16_units().collect();
820           let dir_str = dir_str.append_one(0);
821
822           cb(dir_str.as_ptr())
823       },
824       None => cb(ptr::null())
825     }
826 }
827
828 #[cfg(windows)]
829 fn free_handle(handle: *mut ()) {
830     assert!(unsafe {
831         libc::CloseHandle(mem::transmute(handle)) != 0
832     })
833 }
834
835 #[cfg(unix)]
836 fn free_handle(_handle: *mut ()) {
837     // unix has no process handle object, just a pid
838 }
839
840 #[cfg(unix)]
841 fn translate_status(status: c_int) -> rtio::ProcessExit {
842     #![allow(non_snake_case)]
843     #[cfg(any(target_os = "linux", target_os = "android"))]
844     mod imp {
845         pub fn WIFEXITED(status: i32) -> bool { (status & 0xff) == 0 }
846         pub fn WEXITSTATUS(status: i32) -> i32 { (status >> 8) & 0xff }
847         pub fn WTERMSIG(status: i32) -> i32 { status & 0x7f }
848     }
849
850     #[cfg(any(target_os = "macos",
851               target_os = "ios",
852               target_os = "freebsd",
853               target_os = "dragonfly"))]
854     mod imp {
855         pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
856         pub fn WEXITSTATUS(status: i32) -> i32 { status >> 8 }
857         pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 }
858     }
859
860     if imp::WIFEXITED(status) {
861         rtio::ExitStatus(imp::WEXITSTATUS(status) as int)
862     } else {
863         rtio::ExitSignal(imp::WTERMSIG(status) as int)
864     }
865 }
866
867 /**
868  * Waits for a process to exit and returns the exit code, failing
869  * if there is no process with the specified id.
870  *
871  * Note that this is private to avoid race conditions on unix where if
872  * a user calls waitpid(some_process.get_id()) then some_process.finish()
873  * and some_process.destroy() and some_process.finalize() will then either
874  * operate on a none-existent process or, even worse, on a newer process
875  * with the same id.
876  */
877 #[cfg(windows)]
878 fn waitpid(pid: pid_t, deadline: u64) -> IoResult<rtio::ProcessExit> {
879     use libc::types::os::arch::extra::DWORD;
880     use libc::consts::os::extra::{
881         SYNCHRONIZE,
882         PROCESS_QUERY_INFORMATION,
883         FALSE,
884         STILL_ACTIVE,
885         INFINITE,
886         WAIT_TIMEOUT,
887         WAIT_OBJECT_0,
888     };
889     use libc::funcs::extra::kernel32::{
890         OpenProcess,
891         GetExitCodeProcess,
892         CloseHandle,
893         WaitForSingleObject,
894     };
895
896     unsafe {
897         let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
898                                   FALSE,
899                                   pid as DWORD);
900         if process.is_null() {
901             return Err(super::last_error())
902         }
903
904         loop {
905             let mut status = 0;
906             if GetExitCodeProcess(process, &mut status) == FALSE {
907                 let err = Err(super::last_error());
908                 assert!(CloseHandle(process) != 0);
909                 return err;
910             }
911             if status != STILL_ACTIVE {
912                 assert!(CloseHandle(process) != 0);
913                 return Ok(rtio::ExitStatus(status as int));
914             }
915             let interval = if deadline == 0 {
916                 INFINITE
917             } else {
918                 let now = ::io::timer::now();
919                 if deadline < now {0} else {(deadline - now) as u32}
920             };
921             match WaitForSingleObject(process, interval) {
922                 WAIT_OBJECT_0 => {}
923                 WAIT_TIMEOUT => {
924                     assert!(CloseHandle(process) != 0);
925                     return Err(util::timeout("process wait timed out"))
926                 }
927                 _ => {
928                     let err = Err(super::last_error());
929                     assert!(CloseHandle(process) != 0);
930                     return err
931                 }
932             }
933         }
934     }
935 }
936
937 #[cfg(unix)]
938 fn waitpid(pid: pid_t, deadline: u64) -> IoResult<rtio::ProcessExit> {
939     use std::cmp;
940     use std::comm;
941
942     static mut WRITE_FD: libc::c_int = 0;
943
944     let mut status = 0 as c_int;
945     if deadline == 0 {
946         return match retry(|| unsafe { c::waitpid(pid, &mut status, 0) }) {
947             -1 => fail!("unknown waitpid error: {}", super::last_error().code),
948             _ => Ok(translate_status(status)),
949         }
950     }
951
952     // On unix, wait() and its friends have no timeout parameters, so there is
953     // no way to time out a thread in wait(). From some googling and some
954     // thinking, it appears that there are a few ways to handle timeouts in
955     // wait(), but the only real reasonable one for a multi-threaded program is
956     // to listen for SIGCHLD.
957     //
958     // With this in mind, the waiting mechanism with a timeout barely uses
959     // waitpid() at all. There are a few times that waitpid() is invoked with
960     // WNOHANG, but otherwise all the necessary blocking is done by waiting for
961     // a SIGCHLD to arrive (and that blocking has a timeout). Note, however,
962     // that waitpid() is still used to actually reap the child.
963     //
964     // Signal handling is super tricky in general, and this is no exception. Due
965     // to the async nature of SIGCHLD, we use the self-pipe trick to transmit
966     // data out of the signal handler to the rest of the application. The first
967     // idea would be to have each thread waiting with a timeout to read this
968     // output file descriptor, but a write() is akin to a signal(), not a
969     // broadcast(), so it would only wake up one thread, and possibly the wrong
970     // thread. Hence a helper thread is used.
971     //
972     // The helper thread here is responsible for farming requests for a
973     // waitpid() with a timeout, and then processing all of the wait requests.
974     // By guaranteeing that only this helper thread is reading half of the
975     // self-pipe, we're sure that we'll never lose a SIGCHLD. This helper thread
976     // is also responsible for select() to wait for incoming messages or
977     // incoming SIGCHLD messages, along with passing an appropriate timeout to
978     // select() to wake things up as necessary.
979     //
980     // The ordering of the following statements is also very purposeful. First,
981     // we must be guaranteed that the helper thread is booted and available to
982     // receive SIGCHLD signals, and then we must also ensure that we do a
983     // nonblocking waitpid() at least once before we go ask the sigchld helper.
984     // This prevents the race where the child exits, we boot the helper, and
985     // then we ask for the child's exit status (never seeing a sigchld).
986     //
987     // The actual communication between the helper thread and this thread is
988     // quite simple, just a channel moving data around.
989
990     unsafe { HELPER.boot(register_sigchld, waitpid_helper) }
991
992     match waitpid_nowait(pid) {
993         Some(ret) => return Ok(ret),
994         None => {}
995     }
996
997     let (tx, rx) = channel();
998     unsafe { HELPER.send(NewChild(pid, tx, deadline)); }
999     return match rx.recv_opt() {
1000         Ok(e) => Ok(e),
1001         Err(()) => Err(util::timeout("wait timed out")),
1002     };
1003
1004     // Register a new SIGCHLD handler, returning the reading half of the
1005     // self-pipe plus the old handler registered (return value of sigaction).
1006     //
1007     // Be sure to set up the self-pipe first because as soon as we register a
1008     // handler we're going to start receiving signals.
1009     fn register_sigchld() -> (libc::c_int, c::sigaction) {
1010         unsafe {
1011             let mut pipes = [0, ..2];
1012             assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0);
1013             util::set_nonblocking(pipes[0], true).ok().unwrap();
1014             util::set_nonblocking(pipes[1], true).ok().unwrap();
1015             WRITE_FD = pipes[1];
1016
1017             let mut old: c::sigaction = mem::zeroed();
1018             let mut new: c::sigaction = mem::zeroed();
1019             new.sa_handler = sigchld_handler;
1020             new.sa_flags = c::SA_NOCLDSTOP;
1021             assert_eq!(c::sigaction(c::SIGCHLD, &new, &mut old), 0);
1022             (pipes[0], old)
1023         }
1024     }
1025
1026     // Helper thread for processing SIGCHLD messages
1027     fn waitpid_helper(input: libc::c_int,
1028                       messages: Receiver<Req>,
1029                       (read_fd, old): (libc::c_int, c::sigaction)) {
1030         util::set_nonblocking(input, true).ok().unwrap();
1031         let mut set: c::fd_set = unsafe { mem::zeroed() };
1032         let mut tv: libc::timeval;
1033         let mut active = Vec::<(libc::pid_t, Sender<rtio::ProcessExit>, u64)>::new();
1034         let max = cmp::max(input, read_fd) + 1;
1035
1036         'outer: loop {
1037             // Figure out the timeout of our syscall-to-happen. If we're waiting
1038             // for some processes, then they'll have a timeout, otherwise we
1039             // wait indefinitely for a message to arrive.
1040             //
1041             // FIXME: sure would be nice to not have to scan the entire array
1042             let min = active.iter().map(|a| *a.ref2()).enumerate().min_by(|p| {
1043                 p.val1()
1044             });
1045             let (p, idx) = match min {
1046                 Some((idx, deadline)) => {
1047                     let now = ::io::timer::now();
1048                     let ms = if now < deadline {deadline - now} else {0};
1049                     tv = util::ms_to_timeval(ms);
1050                     (&mut tv as *mut _, idx)
1051                 }
1052                 None => (ptr::null_mut(), -1),
1053             };
1054
1055             // Wait for something to happen
1056             c::fd_set(&mut set, input);
1057             c::fd_set(&mut set, read_fd);
1058             match unsafe { c::select(max, &mut set, ptr::null_mut(),
1059                                      ptr::null_mut(), p) } {
1060                 // interrupted, retry
1061                 -1 if os::errno() == libc::EINTR as int => continue,
1062
1063                 // We read something, break out and process
1064                 1 | 2 => {}
1065
1066                 // Timeout, the pending request is removed
1067                 0 => {
1068                     drop(active.remove(idx));
1069                     continue
1070                 }
1071
1072                 n => fail!("error in select {} ({})", os::errno(), n),
1073             }
1074
1075             // Process any pending messages
1076             if drain(input) {
1077                 loop {
1078                     match messages.try_recv() {
1079                         Ok(NewChild(pid, tx, deadline)) => {
1080                             active.push((pid, tx, deadline));
1081                         }
1082                         Err(comm::Disconnected) => {
1083                             assert!(active.len() == 0);
1084                             break 'outer;
1085                         }
1086                         Err(comm::Empty) => break,
1087                     }
1088                 }
1089             }
1090
1091             // If a child exited (somehow received SIGCHLD), then poll all
1092             // children to see if any of them exited.
1093             //
1094             // We also attempt to be responsible netizens when dealing with
1095             // SIGCHLD by invoking any previous SIGCHLD handler instead of just
1096             // ignoring any previous SIGCHLD handler. Note that we don't provide
1097             // a 1:1 mapping of our handler invocations to the previous handler
1098             // invocations because we drain the `read_fd` entirely. This is
1099             // probably OK because the kernel is already allowed to coalesce
1100             // simultaneous signals, we're just doing some extra coalescing.
1101             //
1102             // Another point of note is that this likely runs the signal handler
1103             // on a different thread than the one that received the signal. I
1104             // *think* this is ok at this time.
1105             //
1106             // The main reason for doing this is to allow stdtest to run native
1107             // tests as well. Both libgreen and libnative are running around
1108             // with process timeouts, but libgreen should get there first
1109             // (currently libuv doesn't handle old signal handlers).
1110             if drain(read_fd) {
1111                 let i: uint = unsafe { mem::transmute(old.sa_handler) };
1112                 if i != 0 {
1113                     assert!(old.sa_flags & c::SA_SIGINFO == 0);
1114                     (old.sa_handler)(c::SIGCHLD);
1115                 }
1116
1117                 // FIXME: sure would be nice to not have to scan the entire
1118                 //        array...
1119                 active.retain(|&(pid, ref tx, _)| {
1120                     match waitpid_nowait(pid) {
1121                         Some(msg) => { tx.send(msg); false }
1122                         None => true,
1123                     }
1124                 });
1125             }
1126         }
1127
1128         // Once this helper thread is done, we re-register the old sigchld
1129         // handler and close our intermediate file descriptors.
1130         unsafe {
1131             assert_eq!(c::sigaction(c::SIGCHLD, &old, ptr::null_mut()), 0);
1132             let _ = libc::close(read_fd);
1133             let _ = libc::close(WRITE_FD);
1134             WRITE_FD = -1;
1135         }
1136     }
1137
1138     // Drain all pending data from the file descriptor, returning if any data
1139     // could be drained. This requires that the file descriptor is in
1140     // nonblocking mode.
1141     fn drain(fd: libc::c_int) -> bool {
1142         let mut ret = false;
1143         loop {
1144             let mut buf = [0u8, ..1];
1145             match unsafe {
1146                 libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void,
1147                            buf.len() as libc::size_t)
1148             } {
1149                 n if n > 0 => { ret = true; }
1150                 0 => return true,
1151                 -1 if util::wouldblock() => return ret,
1152                 n => fail!("bad read {} ({})", os::last_os_error(), n),
1153             }
1154         }
1155     }
1156
1157     // Signal handler for SIGCHLD signals, must be async-signal-safe!
1158     //
1159     // This function will write to the writing half of the "self pipe" to wake
1160     // up the helper thread if it's waiting. Note that this write must be
1161     // nonblocking because if it blocks and the reader is the thread we
1162     // interrupted, then we'll deadlock.
1163     //
1164     // When writing, if the write returns EWOULDBLOCK then we choose to ignore
1165     // it. At that point we're guaranteed that there's something in the pipe
1166     // which will wake up the other end at some point, so we just allow this
1167     // signal to be coalesced with the pending signals on the pipe.
1168     extern fn sigchld_handler(_signum: libc::c_int) {
1169         let msg = 1i;
1170         match unsafe {
1171             libc::write(WRITE_FD, &msg as *const _ as *const libc::c_void, 1)
1172         } {
1173             1 => {}
1174             -1 if util::wouldblock() => {} // see above comments
1175             n => fail!("bad error on write fd: {} {}", n, os::errno()),
1176         }
1177     }
1178 }
1179
1180 fn waitpid_nowait(pid: pid_t) -> Option<rtio::ProcessExit> {
1181     return waitpid_os(pid);
1182
1183     // This code path isn't necessary on windows
1184     #[cfg(windows)]
1185     fn waitpid_os(_pid: pid_t) -> Option<rtio::ProcessExit> { None }
1186
1187     #[cfg(unix)]
1188     fn waitpid_os(pid: pid_t) -> Option<rtio::ProcessExit> {
1189         let mut status = 0 as c_int;
1190         match retry(|| unsafe {
1191             c::waitpid(pid, &mut status, c::WNOHANG)
1192         }) {
1193             n if n == pid => Some(translate_status(status)),
1194             0 => None,
1195             n => fail!("unknown waitpid error `{}`: {}", n,
1196                        super::last_error().code),
1197         }
1198     }
1199 }
1200
1201 #[cfg(test)]
1202 mod tests {
1203
1204     #[test] #[cfg(windows)]
1205     fn test_make_command_line() {
1206         use std::str;
1207         use std::c_str::CString;
1208         use super::make_command_line;
1209
1210         fn test_wrapper(prog: &str, args: &[&str]) -> String {
1211             make_command_line(&prog.to_c_str(),
1212                               args.iter()
1213                                   .map(|a| a.to_c_str())
1214                                   .collect::<Vec<CString>>()
1215                                   .as_slice())
1216         }
1217
1218         assert_eq!(
1219             test_wrapper("prog", ["aaa", "bbb", "ccc"]),
1220             "prog aaa bbb ccc".to_string()
1221         );
1222
1223         assert_eq!(
1224             test_wrapper("C:\\Program Files\\blah\\blah.exe", ["aaa"]),
1225             "\"C:\\Program Files\\blah\\blah.exe\" aaa".to_string()
1226         );
1227         assert_eq!(
1228             test_wrapper("C:\\Program Files\\test", ["aa\"bb"]),
1229             "\"C:\\Program Files\\test\" aa\\\"bb".to_string()
1230         );
1231         assert_eq!(
1232             test_wrapper("echo", ["a b c"]),
1233             "echo \"a b c\"".to_string()
1234         );
1235         assert_eq!(
1236             test_wrapper("\u03c0\u042f\u97f3\u00e6\u221e", []),
1237             "\u03c0\u042f\u97f3\u00e6\u221e".to_string()
1238         );
1239     }
1240 }