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