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