(index<- ) ./libstd/rt/io/process.rs
1 // Copyright 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 //! Bindings for executing child processes
12
13 use prelude::*;
14
15 use libc;
16 use rt::io;
17 use rt::io::io_error;
18 use rt::local::Local;
19 use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};
20
21 // windows values don't matter as long as they're at least one of unix's
22 // TERM/KILL/INT signals
23 #[cfg(windows)] pub static PleaseExitSignal: int = 15;
24 #[cfg(windows)] pub static MustDieSignal: int = 9;
25 #[cfg(not(windows))] pub static PleaseExitSignal: int = libc::SIGTERM as int;
26 #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int;
27
28 pub struct Process {
29 priv handle: ~RtioProcessObject,
30 io: ~[Option<io::PipeStream>],
31 }
32
33 /// This configuration describes how a new process should be spawned. This is
34 /// translated to libuv's own configuration
35 pub struct ProcessConfig<'self> {
36 /// Path to the program to run
37 program: &'self str,
38
39 /// Arguments to pass to the program (doesn't include the program itself)
40 args: &'self [~str],
41
42 /// Optional environment to specify for the program. If this is None, then
43 /// it will inherit the current process's environment.
44 env: Option<&'self [(~str, ~str)]>,
45
46 /// Optional working directory for the new process. If this is None, then
47 /// the current directory of the running process is inherited.
48 cwd: Option<&'self str>,
49
50 /// Any number of streams/file descriptors/pipes may be attached to this
51 /// process. This list enumerates the file descriptors and such for the
52 /// process to be spawned, and the file descriptors inherited will start at
53 /// 0 and go to the length of this array.
54 ///
55 /// Standard file descriptors are:
56 ///
57 /// 0 - stdin
58 /// 1 - stdout
59 /// 2 - stderr
60 io: ~[StdioContainer]
61 }
62
63 /// Describes what to do with a standard io stream for a child process.
64 pub enum StdioContainer {
65 /// This stream will be ignored. This is the equivalent of attaching the
66 /// stream to `/dev/null`
67 Ignored,
68
69 /// The specified file descriptor is inherited for the stream which it is
70 /// specified for.
71 InheritFd(libc::c_int),
72
73 // XXX: these two shouldn't have libuv-specific implementation details
74
75 /// The specified libuv stream is inherited for the corresponding file
76 /// descriptor it is assigned to.
77 // XXX: this needs to be thought out more.
78 //InheritStream(uv::net::StreamWatcher),
79
80 /// Creates a pipe for the specified file descriptor which will be directed
81 /// into the previously-initialized pipe passed in.
82 ///
83 /// The first boolean argument is whether the pipe is readable, and the
84 /// second is whether it is writable. These properties are from the view of
85 /// the *child* process, not the parent process.
86 CreatePipe(io::UnboundPipeStream,
87 bool /* readable */,
88 bool /* writable */),
89 }
90
91 impl Process {
92 /// Creates a new pipe initialized, but not bound to any particular
93 /// source/destination
94 pub fn new(config: ProcessConfig) -> Option<Process> {
95 let process = unsafe {
96 let io: *mut IoFactoryObject = Local::unsafe_borrow();
97 (*io).spawn(config)
98 };
99 match process {
100 Ok((p, io)) => Some(Process{
101 handle: p,
102 io: io.move_iter().map(|p|
103 p.map(|p| io::PipeStream::bind(p))
104 ).collect()
105 }),
106 Err(ioerr) => {
107 io_error::cond.raise(ioerr);
108 None
109 }
110 }
111 }
112
113 /// Returns the process id of this child process
114 pub fn id(&self) -> libc::pid_t { self.handle.id() }
115
116 /// Sends the specified signal to the child process, returning whether the
117 /// signal could be delivered or not.
118 ///
119 /// Note that this is purely a wrapper around libuv's `uv_process_kill`
120 /// function.
121 ///
122 /// If the signal delivery fails, then the `io_error` condition is raised on
123 pub fn signal(&mut self, signal: int) {
124 match self.handle.kill(signal) {
125 Ok(()) => {}
126 Err(err) => {
127 io_error::cond.raise(err)
128 }
129 }
130 }
131
132 /// Wait for the child to exit completely, returning the status that it
133 /// exited with. This function will continue to have the same return value
134 /// after it has been called at least once.
135 pub fn wait(&mut self) -> int { self.handle.wait() }
136 }
137
138 impl Drop for Process {
139 fn drop(&mut self) {
140 // Close all I/O before exiting to ensure that the child doesn't wait
141 // forever to print some text or something similar.
142 for _ in range(0, self.io.len()) {
143 self.io.pop();
144 }
145
146 self.wait();
147 }
148 }
149
150 // Tests for this module can be found in the rtio-processes run-pass test, along
151 // with the justification for why it's not located here.