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