]> git.lizzy.rs Git - rust.git/blob - src/libstd/run.rs
Revert "auto merge of #8645 : alexcrichton/rust/issue-6436-run-non-blocking, r=brson"
[rust.git] / src / libstd / run.rs
1 // Copyright 2012-2013 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 //! Process spawning.
12
13 #[allow(missing_doc)];
14
15 use c_str::ToCStr;
16 use cast;
17 use clone::Clone;
18 use comm::{stream, SharedChan, GenericChan, GenericPort};
19 use io;
20 use libc::{pid_t, c_void, c_int};
21 use libc;
22 use option::{Some, None};
23 use os;
24 use prelude::*;
25 use ptr;
26 use task;
27 use vec::ImmutableVector;
28
29 /**
30  * A value representing a child process.
31  *
32  * The lifetime of this value is linked to the lifetime of the actual
33  * process - the Process destructor calls self.finish() which waits
34  * for the process to terminate.
35  */
36 pub struct Process {
37
38     /// The unique id of the process (this should never be negative).
39     priv pid: pid_t,
40
41     /**
42      * A handle to the process - on unix this will always be NULL, but on
43      * windows it will be a HANDLE to the process, which will prevent the
44      * pid being re-used until the handle is closed.
45      */
46     priv handle: *(),
47
48     /// Some(fd), or None when stdin is being redirected from a fd not created by Process::new.
49     priv input: Option<c_int>,
50
51     /// Some(file), or None when stdout is being redirected to a fd not created by Process::new.
52     priv output: Option<*libc::FILE>,
53
54     /// Some(file), or None when stderr is being redirected to a fd not created by Process::new.
55     priv error: Option<*libc::FILE>,
56
57     /// None until finish() is called.
58     priv exit_code: Option<int>,
59 }
60
61 /// Options that can be given when starting a Process.
62 pub struct ProcessOptions<'self> {
63
64     /**
65      * If this is None then the new process will have the same initial
66      * environment as the parent process.
67      *
68      * If this is Some(vec-of-names-and-values) then the new process will
69      * have an environment containing the given named values only.
70      */
71     env: Option<~[(~str, ~str)]>,
72
73     /**
74      * If this is None then the new process will use the same initial working
75      * directory as the parent process.
76      *
77      * If this is Some(path) then the new process will use the given path
78      * for its initial working directory.
79      */
80     dir: Option<&'self Path>,
81
82     /**
83      * If this is None then a new pipe will be created for the new process's
84      * input and Process.input() will provide a Writer to write to this pipe.
85      *
86      * If this is Some(file-descriptor) then the new process will read its input
87      * from the given file descriptor, Process.input_redirected() will return
88      * true, and Process.input() will fail.
89      */
90     in_fd: Option<c_int>,
91
92     /**
93      * If this is None then a new pipe will be created for the new program's
94      * output and Process.output() will provide a Reader to read from this pipe.
95      *
96      * If this is Some(file-descriptor) then the new process will write its output
97      * to the given file descriptor, Process.output_redirected() will return
98      * true, and Process.output() will fail.
99      */
100     out_fd: Option<c_int>,
101
102     /**
103      * If this is None then a new pipe will be created for the new program's
104      * error stream and Process.error() will provide a Reader to read from this pipe.
105      *
106      * If this is Some(file-descriptor) then the new process will write its error output
107      * to the given file descriptor, Process.error_redirected() will return true, and
108      * and Process.error() will fail.
109      */
110     err_fd: Option<c_int>,
111 }
112
113 impl <'self> ProcessOptions<'self> {
114     /// Return a ProcessOptions that has None in every field.
115     pub fn new<'a>() -> ProcessOptions<'a> {
116         ProcessOptions {
117             env: None,
118             dir: None,
119             in_fd: None,
120             out_fd: None,
121             err_fd: None,
122         }
123     }
124 }
125
126 /// The output of a finished process.
127 pub struct ProcessOutput {
128
129     /// The status (exit code) of the process.
130     status: int,
131
132     /// The data that the process wrote to stdout.
133     output: ~[u8],
134
135     /// The data that the process wrote to stderr.
136     error: ~[u8],
137 }
138
139 impl Process {
140     /**
141      * Spawns a new Process.
142      *
143      * # Arguments
144      *
145      * * prog - The path to an executable.
146      * * args - Vector of arguments to pass to the child process.
147      * * options - Options to configure the environment of the process,
148      *             the working directory and the standard IO streams.
149      */
150     pub fn new(prog: &str, args: &[~str],
151                options: ProcessOptions)
152                -> Process {
153         #[fixed_stack_segment]; #[inline(never)];
154
155         let (in_pipe, in_fd) = match options.in_fd {
156             None => {
157                 let pipe = os::pipe();
158                 (Some(pipe), pipe.input)
159             },
160             Some(fd) => (None, fd)
161         };
162         let (out_pipe, out_fd) = match options.out_fd {
163             None => {
164                 let pipe = os::pipe();
165                 (Some(pipe), pipe.out)
166             },
167             Some(fd) => (None, fd)
168         };
169         let (err_pipe, err_fd) = match options.err_fd {
170             None => {
171                 let pipe = os::pipe();
172                 (Some(pipe), pipe.out)
173             },
174             Some(fd) => (None, fd)
175         };
176
177         let res = spawn_process_os(prog, args, options.env.clone(), options.dir,
178                                    in_fd, out_fd, err_fd);
179
180         unsafe {
181             for pipe in in_pipe.iter() { libc::close(pipe.input); }
182             for pipe in out_pipe.iter() { libc::close(pipe.out); }
183             for pipe in err_pipe.iter() { libc::close(pipe.out); }
184         }
185
186         Process {
187             pid: res.pid,
188             handle: res.handle,
189             input: in_pipe.map(|pipe| pipe.out),
190             output: out_pipe.map(|pipe| os::fdopen(pipe.input)),
191             error: err_pipe.map(|pipe| os::fdopen(pipe.input)),
192             exit_code: None,
193         }
194     }
195
196     /// Returns the unique id of the process
197     pub fn get_id(&self) -> pid_t { self.pid }
198
199     fn input_fd(&mut self) -> c_int {
200         match self.input {
201             Some(fd) => fd,
202             None => fail!("This Process's stdin was redirected to an \
203                            existing file descriptor.")
204         }
205     }
206
207     fn output_file(&mut self) -> *libc::FILE {
208         match self.output {
209             Some(file) => file,
210             None => fail!("This Process's stdout was redirected to an \
211                            existing file descriptor.")
212         }
213     }
214
215     fn error_file(&mut self) -> *libc::FILE {
216         match self.error {
217             Some(file) => file,
218             None => fail!("This Process's stderr was redirected to an \
219                            existing file descriptor.")
220         }
221     }
222
223     /**
224      * Returns whether this process is reading its stdin from an existing file
225      * descriptor rather than a pipe that was created specifically for this
226      * process.
227      *
228      * If this method returns true then self.input() will fail.
229      */
230     pub fn input_redirected(&self) -> bool {
231         self.input.is_none()
232     }
233
234     /**
235      * Returns whether this process is writing its stdout to an existing file
236      * descriptor rather than a pipe that was created specifically for this
237      * process.
238      *
239      * If this method returns true then self.output() will fail.
240      */
241     pub fn output_redirected(&self) -> bool {
242         self.output.is_none()
243     }
244
245     /**
246      * Returns whether this process is writing its stderr to an existing file
247      * descriptor rather than a pipe that was created specifically for this
248      * process.
249      *
250      * If this method returns true then self.error() will fail.
251      */
252     pub fn error_redirected(&self) -> bool {
253         self.error.is_none()
254     }
255
256     /**
257      * Returns an io::Writer that can be used to write to this Process's stdin.
258      *
259      * Fails if this Process's stdin was redirected to an existing file descriptor.
260      */
261     pub fn input(&mut self) -> @io::Writer {
262         // FIXME: the Writer can still be used after self is destroyed: #2625
263        io::fd_writer(self.input_fd(), false)
264     }
265
266     /**
267      * Returns an io::Reader that can be used to read from this Process's stdout.
268      *
269      * Fails if this Process's stdout was redirected to an existing file descriptor.
270      */
271     pub fn output(&mut self) -> @io::Reader {
272         // FIXME: the Reader can still be used after self is destroyed: #2625
273         io::FILE_reader(self.output_file(), false)
274     }
275
276     /**
277      * Returns an io::Reader that can be used to read from this Process's stderr.
278      *
279      * Fails if this Process's stderr was redirected to an existing file descriptor.
280      */
281     pub fn error(&mut self) -> @io::Reader {
282         // FIXME: the Reader can still be used after self is destroyed: #2625
283         io::FILE_reader(self.error_file(), false)
284     }
285
286     /**
287      * Closes the handle to the child process's stdin.
288      *
289      * If this process is reading its stdin from an existing file descriptor, then this
290      * method does nothing.
291      */
292     pub fn close_input(&mut self) {
293         #[fixed_stack_segment]; #[inline(never)];
294         match self.input {
295             Some(-1) | None => (),
296             Some(fd) => {
297                 unsafe {
298                     libc::close(fd);
299                 }
300                 self.input = Some(-1);
301             }
302         }
303     }
304
305     fn close_outputs(&mut self) {
306         #[fixed_stack_segment]; #[inline(never)];
307         fclose_and_null(&mut self.output);
308         fclose_and_null(&mut self.error);
309
310         fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
311             #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
312             match *f_opt {
313                 Some(f) if !f.is_null() => {
314                     unsafe {
315                         libc::fclose(f);
316                         *f_opt = Some(0 as *libc::FILE);
317                     }
318                 },
319                 _ => ()
320             }
321         }
322     }
323
324     /**
325      * Closes the handle to stdin, waits for the child process to terminate,
326      * and returns the exit code.
327      *
328      * If the child has already been finished then the exit code is returned.
329      */
330     pub fn finish(&mut self) -> int {
331         for &code in self.exit_code.iter() {
332             return code;
333         }
334         self.close_input();
335         let code = waitpid(self.pid);
336         self.exit_code = Some(code);
337         return code;
338     }
339
340     /**
341      * Closes the handle to stdin, waits for the child process to terminate, and reads
342      * and returns all remaining output of stdout and stderr, along with the exit code.
343      *
344      * If the child has already been finished then the exit code and any remaining
345      * unread output of stdout and stderr will be returned.
346      *
347      * This method will fail if the child process's stdout or stderr streams were
348      * redirected to existing file descriptors.
349      */
350     pub fn finish_with_output(&mut self) -> ProcessOutput {
351         let output_file = self.output_file();
352         let error_file = self.error_file();
353
354         // Spawn two entire schedulers to read both stdout and sterr
355         // in parallel so we don't deadlock while blocking on one
356         // or the other. FIXME (#2625): Surely there's a much more
357         // clever way to do this.
358         let (p, ch) = stream();
359         let ch = SharedChan::new(ch);
360         let ch_clone = ch.clone();
361         do task::spawn_sched(task::SingleThreaded) {
362             let errput = io::FILE_reader(error_file, false);
363             ch.send((2, errput.read_whole_stream()));
364         }
365         do task::spawn_sched(task::SingleThreaded) {
366             let output = io::FILE_reader(output_file, false);
367             ch_clone.send((1, output.read_whole_stream()));
368         }
369
370         let status = self.finish();
371
372         let (errs, outs) = match (p.recv(), p.recv()) {
373             ((1, o), (2, e)) => (e, o),
374             ((2, e), (1, o)) => (e, o),
375             ((x, _), (y, _)) => {
376                 fail!("unexpected file numbers: %u, %u", x, y);
377             }
378         };
379
380         return ProcessOutput {status: status,
381                               output: outs,
382                               error: errs};
383     }
384
385     fn destroy_internal(&mut self, force: bool) {
386         // if the process has finished, and therefore had waitpid called,
387         // and we kill it, then on unix we might ending up killing a
388         // newer process that happens to have the same (re-used) id
389         if self.exit_code.is_none() {
390             killpid(self.pid, force);
391             self.finish();
392         }
393
394         #[cfg(windows)]
395         fn killpid(pid: pid_t, _force: bool) {
396             #[fixed_stack_segment]; #[inline(never)];
397             unsafe {
398                 libc::funcs::extra::kernel32::TerminateProcess(
399                     cast::transmute(pid), 1);
400             }
401         }
402
403         #[cfg(unix)]
404         fn killpid(pid: pid_t, force: bool) {
405             #[fixed_stack_segment]; #[inline(never)];
406
407             let signal = if force {
408                 libc::consts::os::posix88::SIGKILL
409             } else {
410                 libc::consts::os::posix88::SIGTERM
411             };
412
413             unsafe {
414                 libc::funcs::posix88::signal::kill(pid, signal as c_int);
415             }
416         }
417     }
418
419     /**
420      * Terminates the process, giving it a chance to clean itself up if
421      * this is supported by the operating system.
422      *
423      * On Posix OSs SIGTERM will be sent to the process. On Win32
424      * TerminateProcess(..) will be called.
425      */
426     pub fn destroy(&mut self) { self.destroy_internal(false); }
427
428     /**
429      * Terminates the process as soon as possible without giving it a
430      * chance to clean itself up.
431      *
432      * On Posix OSs SIGKILL will be sent to the process. On Win32
433      * TerminateProcess(..) will be called.
434      */
435     pub fn force_destroy(&mut self) { self.destroy_internal(true); }
436 }
437
438 impl Drop for Process {
439     fn drop(&self) {
440         // FIXME(#4330) Need self by value to get mutability.
441         let mut_self: &mut Process = unsafe { cast::transmute(self) };
442
443         mut_self.finish();
444         mut_self.close_outputs();
445         free_handle(self.handle);
446     }
447 }
448
449 struct SpawnProcessResult {
450     pid: pid_t,
451     handle: *(),
452 }
453
454 #[cfg(windows)]
455 fn spawn_process_os(prog: &str, args: &[~str],
456                     env: Option<~[(~str, ~str)]>,
457                     dir: Option<&Path>,
458                     in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
459     #[fixed_stack_segment]; #[inline(never)];
460
461     use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
462     use libc::consts::os::extra::{
463         TRUE, FALSE,
464         STARTF_USESTDHANDLES,
465         INVALID_HANDLE_VALUE,
466         DUPLICATE_SAME_ACCESS
467     };
468     use libc::funcs::extra::kernel32::{
469         GetCurrentProcess,
470         DuplicateHandle,
471         CloseHandle,
472         CreateProcessA
473     };
474     use libc::funcs::extra::msvcrt::get_osfhandle;
475
476     use sys;
477
478     unsafe {
479
480         let mut si = zeroed_startupinfo();
481         si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
482         si.dwFlags = STARTF_USESTDHANDLES;
483
484         let cur_proc = GetCurrentProcess();
485
486         let orig_std_in = get_osfhandle(in_fd) as HANDLE;
487         if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
488             fail!("failure in get_osfhandle: %s", os::last_os_error());
489         }
490         if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
491                            0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
492             fail!("failure in DuplicateHandle: %s", os::last_os_error());
493         }
494
495         let orig_std_out = get_osfhandle(out_fd) as HANDLE;
496         if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
497             fail!("failure in get_osfhandle: %s", os::last_os_error());
498         }
499         if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
500                            0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
501             fail!("failure in DuplicateHandle: %s", os::last_os_error());
502         }
503
504         let orig_std_err = get_osfhandle(err_fd) as HANDLE;
505         if orig_std_err == INVALID_HANDLE_VALUE as HANDLE {
506             fail!("failure in get_osfhandle: %s", os::last_os_error());
507         }
508         if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
509                            0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
510             fail!("failure in DuplicateHandle: %s", os::last_os_error());
511         }
512
513         let cmd = make_command_line(prog, args);
514         let mut pi = zeroed_process_information();
515         let mut create_err = None;
516
517         do with_envp(env) |envp| {
518             do with_dirp(dir) |dirp| {
519                 do cmd.with_c_str |cmdp| {
520                     let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
521                                                  ptr::mut_null(), ptr::mut_null(), TRUE,
522                                                  0, envp, dirp, &mut si, &mut pi);
523                     if created == FALSE {
524                         create_err = Some(os::last_os_error());
525                     }
526                 }
527             }
528         }
529
530         CloseHandle(si.hStdInput);
531         CloseHandle(si.hStdOutput);
532         CloseHandle(si.hStdError);
533
534         for msg in create_err.iter() {
535             fail!("failure in CreateProcess: %s", *msg);
536         }
537
538         // We close the thread handle because we don't care about keeping the thread id valid,
539         // and we aren't keeping the thread handle around to be able to close it later. We don't
540         // close the process handle however because we want the process id to stay valid at least
541         // until the calling code closes the process handle.
542         CloseHandle(pi.hThread);
543
544         SpawnProcessResult {
545             pid: pi.dwProcessId as pid_t,
546             handle: pi.hProcess as *()
547         }
548     }
549 }
550
551 #[cfg(windows)]
552 fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
553     libc::types::os::arch::extra::STARTUPINFO {
554         cb: 0,
555         lpReserved: ptr::mut_null(),
556         lpDesktop: ptr::mut_null(),
557         lpTitle: ptr::mut_null(),
558         dwX: 0,
559         dwY: 0,
560         dwXSize: 0,
561         dwYSize: 0,
562         dwXCountChars: 0,
563         dwYCountCharts: 0,
564         dwFillAttribute: 0,
565         dwFlags: 0,
566         wShowWindow: 0,
567         cbReserved2: 0,
568         lpReserved2: ptr::mut_null(),
569         hStdInput: ptr::mut_null(),
570         hStdOutput: ptr::mut_null(),
571         hStdError: ptr::mut_null()
572     }
573 }
574
575 #[cfg(windows)]
576 fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
577     libc::types::os::arch::extra::PROCESS_INFORMATION {
578         hProcess: ptr::mut_null(),
579         hThread: ptr::mut_null(),
580         dwProcessId: 0,
581         dwThreadId: 0
582     }
583 }
584
585 // FIXME: this is only pub so it can be tested (see issue #4536)
586 #[cfg(windows)]
587 pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
588     let mut cmd = ~"";
589     append_arg(&mut cmd, prog);
590     for arg in args.iter() {
591         cmd.push_char(' ');
592         append_arg(&mut cmd, *arg);
593     }
594     return cmd;
595
596     fn append_arg(cmd: &mut ~str, arg: &str) {
597         let quote = arg.iter().any(|c| c == ' ' || c == '\t');
598         if quote {
599             cmd.push_char('"');
600         }
601         for i in range(0u, arg.len()) {
602             append_char_at(cmd, arg, i);
603         }
604         if quote {
605             cmd.push_char('"');
606         }
607     }
608
609     fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
610         match arg[i] as char {
611             '"' => {
612                 // Escape quotes.
613                 cmd.push_str("\\\"");
614             }
615             '\\' => {
616                 if backslash_run_ends_in_quote(arg, i) {
617                     // Double all backslashes that are in runs before quotes.
618                     cmd.push_str("\\\\");
619                 } else {
620                     // Pass other backslashes through unescaped.
621                     cmd.push_char('\\');
622                 }
623             }
624             c => {
625                 cmd.push_char(c);
626             }
627         }
628     }
629
630     fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
631         while i < s.len() && s[i] as char == '\\' {
632             i += 1;
633         }
634         return i < s.len() && s[i] as char == '"';
635     }
636 }
637
638 #[cfg(unix)]
639 fn spawn_process_os(prog: &str, args: &[~str],
640                     env: Option<~[(~str, ~str)]>,
641                     dir: Option<&Path>,
642                     in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
643     #[fixed_stack_segment]; #[inline(never)];
644
645     use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
646     use libc::funcs::bsd44::getdtablesize;
647
648     mod rustrt {
649         use libc::c_void;
650
651         #[abi = "cdecl"]
652         extern {
653             pub fn rust_unset_sigprocmask();
654             pub fn rust_set_environ(envp: *c_void);
655         }
656     }
657
658     unsafe {
659
660         let pid = fork();
661         if pid < 0 {
662             fail!("failure in fork: %s", os::last_os_error());
663         } else if pid > 0 {
664             return SpawnProcessResult {pid: pid, handle: ptr::null()};
665         }
666
667         rustrt::rust_unset_sigprocmask();
668
669         if dup2(in_fd, 0) == -1 {
670             fail!("failure in dup2(in_fd, 0): %s", os::last_os_error());
671         }
672         if dup2(out_fd, 1) == -1 {
673             fail!("failure in dup2(out_fd, 1): %s", os::last_os_error());
674         }
675         if dup2(err_fd, 2) == -1 {
676             fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
677         }
678         // close all other fds
679         for fd in range(3, getdtablesize()).invert() {
680             close(fd as c_int);
681         }
682
683         do with_dirp(dir) |dirp| {
684             if !dirp.is_null() && chdir(dirp) == -1 {
685                 fail!("failure in chdir: %s", os::last_os_error());
686             }
687         }
688
689         do with_envp(env) |envp| {
690             if !envp.is_null() {
691                 rustrt::rust_set_environ(envp);
692             }
693             do with_argv(prog, args) |argv| {
694                 execvp(*argv, argv);
695                 // execvp only returns if an error occurred
696                 fail!("failure in execvp: %s", os::last_os_error());
697             }
698         }
699     }
700 }
701
702 #[cfg(unix)]
703 fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
704     use vec;
705
706     // We can't directly convert `str`s into `*char`s, as someone needs to hold
707     // a reference to the intermediary byte buffers. So first build an array to
708     // hold all the ~[u8] byte strings.
709     let mut tmps = vec::with_capacity(args.len() + 1);
710
711     tmps.push(prog.to_c_str());
712
713     for arg in args.iter() {
714         tmps.push(arg.to_c_str());
715     }
716
717     // Next, convert each of the byte strings into a pointer. This is
718     // technically unsafe as the caller could leak these pointers out of our
719     // scope.
720     let mut ptrs = do tmps.map |tmp| {
721         tmp.with_ref(|buf| buf)
722     };
723
724     // Finally, make sure we add a null pointer.
725     ptrs.push(ptr::null());
726
727     ptrs.as_imm_buf(|buf, _| cb(buf))
728 }
729
730 #[cfg(unix)]
731 fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
732     use vec;
733
734     // On posixy systems we can pass a char** for envp, which is a
735     // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
736     // have a temporary buffer to hold the intermediary `~[u8]` byte strings.
737     match env {
738         Some(env) => {
739             let mut tmps = vec::with_capacity(env.len());
740
741             for pair in env.iter() {
742                 // Use of match here is just to workaround limitations
743                 // in the stage0 irrefutable pattern impl.
744                 let kv = fmt!("%s=%s", pair.first(), pair.second());
745                 tmps.push(kv.to_c_str());
746             }
747
748             // Once again, this is unsafe.
749             let mut ptrs = do tmps.map |tmp| {
750                 tmp.with_ref(|buf| buf)
751             };
752             ptrs.push(ptr::null());
753
754             do ptrs.as_imm_buf |buf, _| {
755                 unsafe { cb(cast::transmute(buf)) }
756             }
757         }
758         _ => cb(ptr::null())
759     }
760 }
761
762 #[cfg(windows)]
763 fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
764     // On win32 we pass an "environment block" which is not a char**, but
765     // rather a concatenation of null-terminated k=v\0 sequences, with a final
766     // \0 to terminate.
767     match env {
768         Some(env) => {
769             let mut blk = ~[];
770
771             for pair in env.iter() {
772                 let kv = fmt!("%s=%s", pair.first(), pair.second());
773                 blk.push_all(kv.as_bytes());
774                 blk.push(0);
775             }
776
777             blk.push(0);
778
779             do blk.as_imm_buf |p, _len| {
780                 unsafe { cb(cast::transmute(p)) }
781             }
782         }
783         _ => cb(ptr::mut_null())
784     }
785 }
786
787 fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
788     match d {
789       Some(dir) => dir.with_c_str(|buf| cb(buf)),
790       None => cb(ptr::null())
791     }
792 }
793
794 #[cfg(windows)]
795 fn free_handle(handle: *()) {
796     #[fixed_stack_segment]; #[inline(never)];
797     unsafe {
798         libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
799     }
800 }
801
802 #[cfg(unix)]
803 fn free_handle(_handle: *()) {
804     // unix has no process handle object, just a pid
805 }
806
807 /**
808  * Spawns a process and waits for it to terminate. The process will
809  * inherit the current stdin/stdout/stderr file descriptors.
810  *
811  * # Arguments
812  *
813  * * prog - The path to an executable
814  * * args - Vector of arguments to pass to the child process
815  *
816  * # Return value
817  *
818  * The process's exit code
819  */
820 pub fn process_status(prog: &str, args: &[~str]) -> int {
821     let mut prog = Process::new(prog, args, ProcessOptions {
822         env: None,
823         dir: None,
824         in_fd: Some(0),
825         out_fd: Some(1),
826         err_fd: Some(2)
827     });
828     prog.finish()
829 }
830
831 /**
832  * Spawns a process, records all its output, and waits for it to terminate.
833  *
834  * # Arguments
835  *
836  * * prog - The path to an executable
837  * * args - Vector of arguments to pass to the child process
838  *
839  * # Return value
840  *
841  * The process's stdout/stderr output and exit code.
842  */
843 pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput {
844     let mut prog = Process::new(prog, args, ProcessOptions::new());
845     prog.finish_with_output()
846 }
847
848 /**
849  * Waits for a process to exit and returns the exit code, failing
850  * if there is no process with the specified id.
851  *
852  * Note that this is private to avoid race conditions on unix where if
853  * a user calls waitpid(some_process.get_id()) then some_process.finish()
854  * and some_process.destroy() and some_process.finalize() will then either
855  * operate on a none-existent process or, even worse, on a newer process
856  * with the same id.
857  */
858 fn waitpid(pid: pid_t) -> int {
859     return waitpid_os(pid);
860
861     #[cfg(windows)]
862     fn waitpid_os(pid: pid_t) -> int {
863         #[fixed_stack_segment]; #[inline(never)];
864
865         use libc::types::os::arch::extra::DWORD;
866         use libc::consts::os::extra::{
867             SYNCHRONIZE,
868             PROCESS_QUERY_INFORMATION,
869             FALSE,
870             STILL_ACTIVE,
871             INFINITE,
872             WAIT_FAILED
873         };
874         use libc::funcs::extra::kernel32::{
875             OpenProcess,
876             GetExitCodeProcess,
877             CloseHandle,
878             WaitForSingleObject
879         };
880
881         unsafe {
882
883             let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
884             if proc.is_null() {
885                 fail!("failure in OpenProcess: %s", os::last_os_error());
886             }
887
888             loop {
889                 let mut status = 0;
890                 if GetExitCodeProcess(proc, &mut status) == FALSE {
891                     CloseHandle(proc);
892                     fail!("failure in GetExitCodeProcess: %s", os::last_os_error());
893                 }
894                 if status != STILL_ACTIVE {
895                     CloseHandle(proc);
896                     return status as int;
897                 }
898                 if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
899                     CloseHandle(proc);
900                     fail!("failure in WaitForSingleObject: %s", os::last_os_error());
901                 }
902             }
903         }
904     }
905
906     #[cfg(unix)]
907     fn waitpid_os(pid: pid_t) -> int {
908         #[fixed_stack_segment]; #[inline(never)];
909
910         use libc::funcs::posix01::wait::*;
911
912         #[cfg(target_os = "linux")]
913         #[cfg(target_os = "android")]
914         fn WIFEXITED(status: i32) -> bool {
915             (status & 0xffi32) == 0i32
916         }
917
918         #[cfg(target_os = "macos")]
919         #[cfg(target_os = "freebsd")]
920         fn WIFEXITED(status: i32) -> bool {
921             (status & 0x7fi32) == 0i32
922         }
923
924         #[cfg(target_os = "linux")]
925         #[cfg(target_os = "android")]
926         fn WEXITSTATUS(status: i32) -> i32 {
927             (status >> 8i32) & 0xffi32
928         }
929
930         #[cfg(target_os = "macos")]
931         #[cfg(target_os = "freebsd")]
932         fn WEXITSTATUS(status: i32) -> i32 {
933             status >> 8i32
934         }
935
936         let mut status = 0 as c_int;
937         if unsafe { waitpid(pid, &mut status, 0) } == -1 {
938             fail!("failure in waitpid: %s", os::last_os_error());
939         }
940
941         return if WIFEXITED(status) {
942             WEXITSTATUS(status) as int
943         } else {
944             1
945         };
946     }
947 }
948
949 #[cfg(test)]
950 mod tests {
951     use io;
952     use libc::c_int;
953     use option::{Option, None, Some};
954     use os;
955     use path::Path;
956     use run;
957     use str;
958     use unstable::running_on_valgrind;
959
960     #[test]
961     #[cfg(windows)]
962     fn test_make_command_line() {
963         assert_eq!(
964             run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
965             ~"prog aaa bbb ccc"
966         );
967         assert_eq!(
968             run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
969             ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
970         );
971         assert_eq!(
972             run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
973             ~"\"C:\\Program Files\\test\" aa\\\"bb"
974         );
975         assert_eq!(
976             run::make_command_line("echo", [~"a b c"]),
977             ~"echo \"a b c\""
978         );
979     }
980
981     #[test]
982     #[cfg(not(target_os="android"))]
983     fn test_process_status() {
984         assert_eq!(run::process_status("false", []), 1);
985         assert_eq!(run::process_status("true", []), 0);
986     }
987     #[test]
988     #[cfg(target_os="android")]
989     fn test_process_status() {
990         assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"false"]), 1);
991         assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"true"]), 0);
992     }
993
994     #[test]
995     #[cfg(not(target_os="android"))]
996     fn test_process_output_output() {
997
998         let run::ProcessOutput {status, output, error}
999              = run::process_output("echo", [~"hello"]);
1000         let output_str = str::from_bytes(output);
1001
1002         assert_eq!(status, 0);
1003         assert_eq!(output_str.trim().to_owned(), ~"hello");
1004         // FIXME #7224
1005         if !running_on_valgrind() {
1006             assert_eq!(error, ~[]);
1007         }
1008     }
1009     #[test]
1010     #[cfg(target_os="android")]
1011     fn test_process_output_output() {
1012
1013         let run::ProcessOutput {status, output, error}
1014              = run::process_output("/system/bin/sh", [~"-c",~"echo hello"]);
1015         let output_str = str::from_bytes(output);
1016
1017         assert_eq!(status, 0);
1018         assert_eq!(output_str.trim().to_owned(), ~"hello");
1019         // FIXME #7224
1020         if !running_on_valgrind() {
1021             assert_eq!(error, ~[]);
1022         }
1023     }
1024
1025     #[test]
1026     #[cfg(not(target_os="android"))]
1027     fn test_process_output_error() {
1028
1029         let run::ProcessOutput {status, output, error}
1030              = run::process_output("mkdir", [~"."]);
1031
1032         assert_eq!(status, 1);
1033         assert_eq!(output, ~[]);
1034         assert!(!error.is_empty());
1035     }
1036     #[test]
1037     #[cfg(target_os="android")]
1038     fn test_process_output_error() {
1039
1040         let run::ProcessOutput {status, output, error}
1041              = run::process_output("/system/bin/mkdir", [~"."]);
1042
1043         assert_eq!(status, 255);
1044         assert_eq!(output, ~[]);
1045         assert!(!error.is_empty());
1046     }
1047
1048     #[test]
1049     fn test_pipes() {
1050
1051         let pipe_in = os::pipe();
1052         let pipe_out = os::pipe();
1053         let pipe_err = os::pipe();
1054
1055         let mut proc = run::Process::new("cat", [], run::ProcessOptions {
1056             dir: None,
1057             env: None,
1058             in_fd: Some(pipe_in.input),
1059             out_fd: Some(pipe_out.out),
1060             err_fd: Some(pipe_err.out)
1061         });
1062
1063         assert!(proc.input_redirected());
1064         assert!(proc.output_redirected());
1065         assert!(proc.error_redirected());
1066
1067         os::close(pipe_in.input);
1068         os::close(pipe_out.out);
1069         os::close(pipe_err.out);
1070
1071         let expected = ~"test";
1072         writeclose(pipe_in.out, expected);
1073         let actual = readclose(pipe_out.input);
1074         readclose(pipe_err.input);
1075         proc.finish();
1076
1077         assert_eq!(expected, actual);
1078     }
1079
1080     fn writeclose(fd: c_int, s: &str) {
1081         let writer = io::fd_writer(fd, false);
1082         writer.write_str(s);
1083         os::close(fd);
1084     }
1085
1086     fn readclose(fd: c_int) -> ~str {
1087         #[fixed_stack_segment]; #[inline(never)];
1088
1089         unsafe {
1090             let file = os::fdopen(fd);
1091             let reader = io::FILE_reader(file, false);
1092             let buf = reader.read_whole_stream();
1093             os::fclose(file);
1094             str::from_bytes(buf)
1095         }
1096     }
1097
1098     #[test]
1099     #[cfg(not(target_os="android"))]
1100     fn test_finish_once() {
1101         let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
1102         assert_eq!(prog.finish(), 1);
1103     }
1104     #[test]
1105     #[cfg(target_os="android")]
1106     fn test_finish_once() {
1107         let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
1108                                          run::ProcessOptions::new());
1109         assert_eq!(prog.finish(), 1);
1110     }
1111
1112     #[test]
1113     #[cfg(not(target_os="android"))]
1114     fn test_finish_twice() {
1115         let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
1116         assert_eq!(prog.finish(), 1);
1117         assert_eq!(prog.finish(), 1);
1118     }
1119     #[test]
1120     #[cfg(target_os="android")]
1121     fn test_finish_twice() {
1122         let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
1123                                          run::ProcessOptions::new());
1124         assert_eq!(prog.finish(), 1);
1125         assert_eq!(prog.finish(), 1);
1126     }
1127
1128     #[test]
1129     #[cfg(not(target_os="android"))]
1130     fn test_finish_with_output_once() {
1131
1132         let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
1133         let run::ProcessOutput {status, output, error}
1134             = prog.finish_with_output();
1135         let output_str = str::from_bytes(output);
1136
1137         assert_eq!(status, 0);
1138         assert_eq!(output_str.trim().to_owned(), ~"hello");
1139         // FIXME #7224
1140         if !running_on_valgrind() {
1141             assert_eq!(error, ~[]);
1142         }
1143     }
1144     #[test]
1145     #[cfg(target_os="android")]
1146     fn test_finish_with_output_once() {
1147
1148         let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
1149                                          run::ProcessOptions::new());
1150         let run::ProcessOutput {status, output, error}
1151             = prog.finish_with_output();
1152         let output_str = str::from_bytes(output);
1153
1154         assert_eq!(status, 0);
1155         assert_eq!(output_str.trim().to_owned(), ~"hello");
1156         // FIXME #7224
1157         if !running_on_valgrind() {
1158             assert_eq!(error, ~[]);
1159         }
1160     }
1161
1162     #[test]
1163     #[cfg(not(target_os="android"))]
1164     fn test_finish_with_output_twice() {
1165
1166         let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
1167         let run::ProcessOutput {status, output, error}
1168             = prog.finish_with_output();
1169
1170         let output_str = str::from_bytes(output);
1171
1172         assert_eq!(status, 0);
1173         assert_eq!(output_str.trim().to_owned(), ~"hello");
1174         // FIXME #7224
1175         if !running_on_valgrind() {
1176             assert_eq!(error, ~[]);
1177         }
1178
1179         let run::ProcessOutput {status, output, error}
1180             = prog.finish_with_output();
1181
1182         assert_eq!(status, 0);
1183         assert_eq!(output, ~[]);
1184         // FIXME #7224
1185         if !running_on_valgrind() {
1186             assert_eq!(error, ~[]);
1187         }
1188     }
1189     #[test]
1190     #[cfg(target_os="android")]
1191     fn test_finish_with_output_twice() {
1192
1193         let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
1194                                          run::ProcessOptions::new());
1195         let run::ProcessOutput {status, output, error}
1196             = prog.finish_with_output();
1197
1198         let output_str = str::from_bytes(output);
1199
1200         assert_eq!(status, 0);
1201         assert_eq!(output_str.trim().to_owned(), ~"hello");
1202         // FIXME #7224
1203         if !running_on_valgrind() {
1204             assert_eq!(error, ~[]);
1205         }
1206
1207         let run::ProcessOutput {status, output, error}
1208             = prog.finish_with_output();
1209
1210         assert_eq!(status, 0);
1211         assert_eq!(output, ~[]);
1212         // FIXME #7224
1213         if !running_on_valgrind() {
1214             assert_eq!(error, ~[]);
1215         }
1216     }
1217
1218     #[test]
1219     #[should_fail]
1220     #[cfg(not(windows),not(target_os="android"))]
1221     fn test_finish_with_output_redirected() {
1222         let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions {
1223             env: None,
1224             dir: None,
1225             in_fd: Some(0),
1226             out_fd: Some(1),
1227             err_fd: Some(2)
1228         });
1229         // this should fail because it is not valid to read the output when it was redirected
1230         prog.finish_with_output();
1231     }
1232     #[test]
1233     #[should_fail]
1234     #[cfg(not(windows),target_os="android")]
1235     fn test_finish_with_output_redirected() {
1236         let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
1237                                          run::ProcessOptions {
1238             env: None,
1239             dir: None,
1240             in_fd: Some(0),
1241             out_fd: Some(1),
1242             err_fd: Some(2)
1243         });
1244         // this should fail because it is not valid to read the output when it was redirected
1245         prog.finish_with_output();
1246     }
1247
1248     #[cfg(unix,not(target_os="android"))]
1249     fn run_pwd(dir: Option<&Path>) -> run::Process {
1250         run::Process::new("pwd", [], run::ProcessOptions {
1251             dir: dir,
1252             .. run::ProcessOptions::new()
1253         })
1254     }
1255     #[cfg(unix,target_os="android")]
1256     fn run_pwd(dir: Option<&Path>) -> run::Process {
1257         run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions {
1258             dir: dir,
1259             .. run::ProcessOptions::new()
1260         })
1261     }
1262
1263     #[cfg(windows)]
1264     fn run_pwd(dir: Option<&Path>) -> run::Process {
1265         run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions {
1266             dir: dir,
1267             .. run::ProcessOptions::new()
1268         })
1269     }
1270
1271     #[test]
1272     fn test_keep_current_working_dir() {
1273         let mut prog = run_pwd(None);
1274
1275         let output = str::from_bytes(prog.finish_with_output().output);
1276         let parent_dir = os::getcwd().normalize();
1277         let child_dir = Path(output.trim()).normalize();
1278
1279         let parent_stat = parent_dir.stat().unwrap();
1280         let child_stat = child_dir.stat().unwrap();
1281
1282         assert_eq!(parent_stat.st_dev, child_stat.st_dev);
1283         assert_eq!(parent_stat.st_ino, child_stat.st_ino);
1284     }
1285
1286     #[test]
1287     fn test_change_working_directory() {
1288         // test changing to the parent of os::getcwd() because we know
1289         // the path exists (and os::getcwd() is not expected to be root)
1290         let parent_dir = os::getcwd().dir_path().normalize();
1291         let mut prog = run_pwd(Some(&parent_dir));
1292
1293         let output = str::from_bytes(prog.finish_with_output().output);
1294         let child_dir = Path(output.trim()).normalize();
1295
1296         let parent_stat = parent_dir.stat().unwrap();
1297         let child_stat = child_dir.stat().unwrap();
1298
1299         assert_eq!(parent_stat.st_dev, child_stat.st_dev);
1300         assert_eq!(parent_stat.st_ino, child_stat.st_ino);
1301     }
1302
1303     #[cfg(unix,not(target_os="android"))]
1304     fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
1305         run::Process::new("env", [], run::ProcessOptions {
1306             env: env,
1307             .. run::ProcessOptions::new()
1308         })
1309     }
1310     #[cfg(unix,target_os="android")]
1311     fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
1312         run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
1313             env: env,
1314             .. run::ProcessOptions::new()
1315         })
1316     }
1317
1318     #[cfg(windows)]
1319     fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
1320         run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
1321             env: env,
1322             .. run::ProcessOptions::new()
1323         })
1324     }
1325
1326     #[test]
1327     #[cfg(not(target_os="android"))]
1328     fn test_inherit_env() {
1329         if running_on_valgrind() { return; }
1330
1331         let mut prog = run_env(None);
1332         let output = str::from_bytes(prog.finish_with_output().output);
1333
1334         let r = os::env();
1335         for &(ref k, ref v) in r.iter() {
1336             // don't check windows magical empty-named variables
1337             assert!(k.is_empty() || output.contains(fmt!("%s=%s", *k, *v)));
1338         }
1339     }
1340     #[test]
1341     #[cfg(target_os="android")]
1342     fn test_inherit_env() {
1343         if running_on_valgrind() { return; }
1344
1345         let mut prog = run_env(None);
1346         let output = str::from_bytes(prog.finish_with_output().output);
1347
1348         let r = os::env();
1349         for &(ref k, ref v) in r.iter() {
1350             // don't check android RANDOM variables
1351             if *k != ~"RANDOM" {
1352                 assert!(output.contains(fmt!("%s=%s", *k, *v)) ||
1353                         output.contains(fmt!("%s=\'%s\'", *k, *v)));
1354             }
1355         }
1356     }
1357
1358     #[test]
1359     fn test_add_to_env() {
1360
1361         let mut new_env = os::env();
1362         new_env.push((~"RUN_TEST_NEW_ENV", ~"123"));
1363
1364         let mut prog = run_env(Some(new_env));
1365         let output = str::from_bytes(prog.finish_with_output().output);
1366
1367         assert!(output.contains("RUN_TEST_NEW_ENV=123"));
1368     }
1369 }