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.
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.
15 use libc::{pid_t, c_void, c_int};
16 use comm::{stream, SharedChan, GenericChan, GenericPort};
17 use option::{Some, None};
26 use libc::{c_int, c_void};
32 unsafe fn rust_run_program(argv: **libc::c_char,
37 err_fd: c_int) -> run::RunProgramResult;
38 unsafe fn rust_process_wait(pid: c_int) -> c_int;
42 pub struct RunProgramResult {
43 // the process id of the program, or -1 if in case of errors
45 // a handle to the process - on unix this will always be NULL, but on windows it will be a
46 // HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
50 /// A value representing a child process
55 priv out_file: *libc::FILE,
56 priv err_file: *libc::FILE,
60 impl Drop for Program {
62 // FIXME #4943: transmute is bad.
63 let mut_self: &mut Program = unsafe { cast::transmute(self) };
66 mut_self.close_outputs();
67 free_handle(self.handle);
73 /// Returns the process id of the program
74 fn get_id(&mut self) -> pid_t { self.pid }
76 /// Returns an io::Writer that can be used to write to stdin
77 fn input(&mut self) -> @io::Writer {
78 io::fd_writer(self.in_fd, false)
81 /// Returns an io::Reader that can be used to read from stdout
82 fn output(&mut self) -> @io::Reader {
83 io::FILE_reader(self.out_file, false)
86 /// Returns an io::Reader that can be used to read from stderr
87 fn err(&mut self) -> @io::Reader {
88 io::FILE_reader(self.err_file, false)
91 /// Closes the handle to the child processes standard input
92 fn close_input(&mut self) {
93 let invalid_fd = -1i32;
94 if self.in_fd != invalid_fd {
96 libc::close(self.in_fd);
98 self.in_fd = invalid_fd;
102 priv fn close_outputs(&mut self) {
104 fclose_and_null(&mut self.out_file);
105 fclose_and_null(&mut self.err_file);
110 * Waits for the child process to terminate. Closes the handle
111 * to stdin if necessary.
113 fn finish(&mut self) -> int {
114 if self.finished { return 0; }
115 self.finished = true;
117 return waitpid(self.pid);
120 priv fn destroy_internal(&mut self, force: bool) {
121 killpid(self.pid, force);
123 self.close_outputs();
126 fn killpid(pid: pid_t, _force: bool) {
128 libc::funcs::extra::kernel32::TerminateProcess(
129 cast::transmute(pid), 1);
134 fn killpid(pid: pid_t, force: bool) {
135 let signal = if force {
136 libc::consts::os::posix88::SIGKILL
138 libc::consts::os::posix88::SIGTERM
142 libc::funcs::posix88::signal::kill(pid, signal as c_int);
148 * Terminate the program, giving it a chance to clean itself up if
149 * this is supported by the operating system.
151 * On Posix OSs SIGTERM will be sent to the process. On Win32
152 * TerminateProcess(..) will be called.
154 fn destroy(&mut self) { self.destroy_internal(false); }
157 * Terminate the program as soon as possible without giving it a
158 * chance to clean itself up.
160 * On Posix OSs SIGKILL will be sent to the process. On Win32
161 * TerminateProcess(..) will be called.
163 fn force_destroy(&mut self) { self.destroy_internal(true); }
168 * Run a program, providing stdin, stdout and stderr handles
172 * * prog - The path to an executable
173 * * args - Vector of arguments to pass to the child process
174 * * env - optional env-modification for child
175 * * dir - optional dir to run child in (default current dir)
176 * * in_fd - A file descriptor for the child to use as std input
177 * * out_fd - A file descriptor for the child to use as std output
178 * * err_fd - A file descriptor for the child to use as std error
182 * The process id of the spawned process
184 pub fn spawn_process(prog: &str, args: &[~str],
185 env: &Option<~[(~str,~str)]>,
187 in_fd: c_int, out_fd: c_int, err_fd: c_int) -> pid_t {
189 let res = spawn_process_internal(prog, args, env, dir, in_fd, out_fd, err_fd);
190 free_handle(res.handle);
194 fn spawn_process_internal(prog: &str, args: &[~str],
195 env: &Option<~[(~str,~str)]>,
197 in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult {
199 do with_argv(prog, args) |argv| {
200 do with_envp(env) |envp| {
201 do with_dirp(dir) |dirp| {
202 rustrt::rust_run_program(argv, envp, dirp, in_fd, out_fd, err_fd)
209 fn with_argv<T>(prog: &str, args: &[~str],
210 cb: &fn(**libc::c_char) -> T) -> T {
211 let mut argptrs = str::as_c_str(prog, |b| ~[b]);
213 for vec::each(args) |arg| {
216 argptrs.push_all(str::as_c_str(*t, |b| ~[b]));
218 argptrs.push(ptr::null());
219 vec::as_imm_buf(argptrs, |buf, _len| cb(buf))
223 fn with_envp<T>(env: &Option<~[(~str,~str)]>,
224 cb: &fn(*c_void) -> T) -> T {
225 // On posixy systems we can pass a char** for envp, which is
226 // a null-terminated array of "k=v\n" strings.
228 Some(ref es) if !vec::is_empty(*es) => {
232 for vec::each(*es) |e| {
234 let t = @(fmt!("%s=%s", k, v));
236 ptrs.push_all(str::as_c_str(*t, |b| ~[b]));
238 ptrs.push(ptr::null());
239 vec::as_imm_buf(ptrs, |p, _len|
240 unsafe { cb(::cast::transmute(p)) }
248 fn with_envp<T>(env: &Option<~[(~str,~str)]>,
249 cb: &fn(*c_void) -> T) -> T {
250 // On win32 we pass an "environment block" which is not a char**, but
251 // rather a concatenation of null-terminated k=v\0 sequences, with a final
255 Some(ref es) if !vec::is_empty(*es) => {
256 let mut blk : ~[u8] = ~[];
257 for vec::each(*es) |e| {
259 let t = fmt!("%s=%s", k, v);
260 let mut v : ~[u8] = ::cast::transmute(t);
265 vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p)))
272 fn with_dirp<T>(d: &Option<~str>,
273 cb: &fn(*libc::c_char) -> T) -> T {
275 Some(ref dir) => str::as_c_str(*dir, cb),
276 None => cb(ptr::null())
280 /// helper function that closes non-NULL files and then makes them NULL
281 priv unsafe fn fclose_and_null(f: &mut *libc::FILE) {
282 if *f != 0 as *libc::FILE {
284 *f = 0 as *libc::FILE;
289 priv fn free_handle(handle: *()) {
291 libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
296 priv fn free_handle(_handle: *()) {
297 // unix has no process handle object, just a pid
301 * Spawns a process and waits for it to terminate
305 * * prog - The path to an executable
306 * * args - Vector of arguments to pass to the child process
310 * The process's exit code
312 pub fn run_program(prog: &str, args: &[~str]) -> int {
313 let res = spawn_process_internal(prog, args, &None, &None,
315 if res.pid == -1 as pid_t { fail!(); }
317 let code = waitpid(res.pid);
318 free_handle(res.handle);
323 * Spawns a process and returns a Program
325 * The returned value is a <Program> object that can be used for sending and
326 * receiving data over the standard file descriptors. The class will ensure
327 * that file descriptors are closed properly.
331 * * prog - The path to an executable
332 * * args - Vector of arguments to pass to the child process
338 pub fn start_program(prog: &str, args: &[~str]) -> Program {
339 let pipe_input = os::pipe();
340 let pipe_output = os::pipe();
341 let pipe_err = os::pipe();
343 spawn_process_internal(prog, args, &None, &None,
344 pipe_input.in, pipe_output.out,
348 if res.pid == -1 as pid_t { fail!(); }
349 libc::close(pipe_input.in);
350 libc::close(pipe_output.out);
351 libc::close(pipe_err.out);
357 in_fd: pipe_input.out,
358 out_file: os::fdopen(pipe_output.in),
359 err_file: os::fdopen(pipe_err.in),
364 fn read_all(rd: @io::Reader) -> ~str {
365 let buf = io::with_bytes_writer(|wr| {
366 let mut bytes = [0, ..4096];
368 let nread = rd.read(bytes, bytes.len());
369 wr.write(bytes.slice(0, nread));
375 pub struct ProgramOutput {status: int, out: ~str, err: ~str}
378 * Spawns a process, waits for it to exit, and returns the exit code, and
379 * contents of stdout and stderr.
383 * * prog - The path to an executable
384 * * args - Vector of arguments to pass to the child process
388 * A record, {status: int, out: str, err: str} containing the exit code,
389 * the contents of stdout and the contents of stderr.
391 pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
392 let pipe_in = os::pipe();
393 let pipe_out = os::pipe();
394 let pipe_err = os::pipe();
395 let res = spawn_process_internal(prog, args, &None, &None,
396 pipe_in.in, pipe_out.out, pipe_err.out);
398 os::close(pipe_in.in);
399 os::close(pipe_out.out);
400 os::close(pipe_err.out);
401 if res.pid == -1i32 {
402 os::close(pipe_in.out);
403 os::close(pipe_out.in);
404 os::close(pipe_err.in);
408 os::close(pipe_in.out);
410 // Spawn two entire schedulers to read both stdout and sterr
411 // in parallel so we don't deadlock while blocking on one
412 // or the other. FIXME (#2625): Surely there's a much more
413 // clever way to do this.
414 let (p, ch) = stream();
415 let ch = SharedChan::new(ch);
416 let ch_clone = ch.clone();
417 do task::spawn_sched(task::SingleThreaded) {
418 let errput = readclose(pipe_err.in);
419 ch.send((2, errput));
421 do task::spawn_sched(task::SingleThreaded) {
422 let output = readclose(pipe_out.in);
423 ch_clone.send((1, output));
426 let status = waitpid(res.pid);
427 free_handle(res.handle);
433 let stream = p.recv();
442 fail!(fmt!("program_output received an unexpected file \
448 return ProgramOutput {status: status,
453 pub fn writeclose(fd: c_int, s: ~str) {
456 error!("writeclose %d, %s", fd as int, s);
457 let writer = io::fd_writer(fd, false);
463 pub fn readclose(fd: c_int) -> ~str {
465 let file = os::fdopen(fd);
466 let reader = io::FILE_reader(file, false);
467 let buf = io::with_bytes_writer(|writer| {
468 let mut bytes = [0, ..4096];
469 while !reader.eof() {
470 let nread = reader.read(bytes, bytes.len());
471 writer.write(bytes.slice(0, nread));
480 * Waits for a process to exit and returns the exit code, failing
481 * if there is no process with the specified id.
483 pub fn waitpid(pid: pid_t) -> int {
484 return waitpid_os(pid);
487 fn waitpid_os(pid: pid_t) -> int {
488 let status = unsafe { rustrt::rust_process_wait(pid) };
490 fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error()));
492 return status as int;
496 fn waitpid_os(pid: pid_t) -> int {
498 use libc::funcs::posix01::wait::*;
500 #[cfg(target_os = "linux")]
501 #[cfg(target_os = "android")]
502 fn WIFEXITED(status: i32) -> bool {
503 (status & 0xffi32) == 0i32
506 #[cfg(target_os = "macos")]
507 #[cfg(target_os = "freebsd")]
508 fn WIFEXITED(status: i32) -> bool {
509 (status & 0x7fi32) == 0i32
512 #[cfg(target_os = "linux")]
513 #[cfg(target_os = "android")]
514 fn WEXITSTATUS(status: i32) -> i32 {
515 (status >> 8i32) & 0xffi32
518 #[cfg(target_os = "macos")]
519 #[cfg(target_os = "freebsd")]
520 fn WEXITSTATUS(status: i32) -> i32 {
524 let mut status = 0 as c_int;
525 if unsafe { waitpid(pid, &mut status, 0) } == -1 {
526 fail!(fmt!("failure in waitpid: %s", os::last_os_error()));
529 return if WIFEXITED(status) {
530 WEXITSTATUS(status) as int
543 use run::{readclose, writeclose};
546 // Regression test for memory leaks
549 run::run_program("echo", []);
550 run::start_program("echo", []);
551 run::program_output("echo", []);
555 #[allow(non_implicitly_copyable_typarams)]
557 let pipe_in = os::pipe();
558 let pipe_out = os::pipe();
559 let pipe_err = os::pipe();
563 "cat", [], &None, &None,
564 pipe_in.in, pipe_out.out, pipe_err.out);
565 os::close(pipe_in.in);
566 os::close(pipe_out.out);
567 os::close(pipe_err.out);
569 if pid == -1i32 { fail!(); }
570 let expected = ~"test";
571 writeclose(pipe_in.out, copy expected);
572 let actual = readclose(pipe_out.in);
573 readclose(pipe_err.in);
576 debug!(copy expected);
578 assert!((expected == actual));
583 let pid = run::spawn_process("false", [],
586 let status = run::waitpid(pid);
587 assert!(status == 1);
592 #[ignore(cfg(windows))]
593 fn waitpid_non_existant_pid() {
594 run::waitpid(123456789); // assume that this pid doesn't exist
598 fn test_destroy_once() {
599 let mut p = run::start_program("echo", []);
600 p.destroy(); // this shouldn't crash (and nor should the destructor)
604 fn test_destroy_twice() {
605 let mut p = run::start_program("echo", []);
606 p.destroy(); // this shouldnt crash...
607 p.destroy(); // ...and nor should this (and nor should the destructor)
610 #[cfg(unix)] // there is no way to sleep on windows from inside libcore...
611 fn test_destroy_actually_kills(force: bool) {
612 let path = Path(fmt!("test/core-run-test-destroy-actually-kills-%?.tmp", force));
614 os::remove_file(&path);
616 let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str());
617 let mut p = run::start_program("sh", [~"-c", cmd]);
619 p.destroy(); // destroy the program before it has a chance to echo its message
622 // wait to ensure the program is really destroyed and not just waiting itself
626 // the program should not have had chance to echo its message
627 assert!(!path.exists());
632 fn test_unforced_destroy_actually_kills() {
633 test_destroy_actually_kills(false);
638 fn test_forced_destroy_actually_kills() {
639 test_destroy_actually_kills(true);