]>
Commit | Line | Data |
---|---|---|
e74abb32 | 1 | use crate::convert::TryInto; |
e74abb32 | 2 | use crate::fmt; |
60c5eb7d | 3 | use crate::io; |
532ac7d7 XL |
4 | use crate::mem; |
5 | use crate::ptr; | |
476ff2be | 6 | |
532ac7d7 | 7 | use crate::sys::process::process_common::*; |
60c5eb7d | 8 | use crate::sys::process::zircon::{zx_handle_t, Handle}; |
532ac7d7 | 9 | |
e74abb32 | 10 | use libc::{c_int, size_t}; |
476ff2be SL |
11 | |
12 | //////////////////////////////////////////////////////////////////////////////// | |
13 | // Command | |
14 | //////////////////////////////////////////////////////////////////////////////// | |
15 | ||
16 | impl Command { | |
60c5eb7d XL |
17 | pub fn spawn( |
18 | &mut self, | |
19 | default: Stdio, | |
20 | needs_stdin: bool, | |
21 | ) -> io::Result<(Process, StdioPipes)> { | |
ff7c6d11 XL |
22 | let envp = self.capture_env(); |
23 | ||
476ff2be | 24 | if self.saw_nul() { |
60c5eb7d XL |
25 | return Err(io::Error::new( |
26 | io::ErrorKind::InvalidInput, | |
27 | "nul byte found in provided data", | |
28 | )); | |
476ff2be SL |
29 | } |
30 | ||
31 | let (ours, theirs) = self.setup_io(default, needs_stdin)?; | |
32 | ||
ff7c6d11 | 33 | let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? }; |
476ff2be | 34 | |
8bb4bdeb | 35 | Ok((Process { handle: Handle::new(process_handle) }, ours)) |
476ff2be SL |
36 | } |
37 | ||
38 | pub fn exec(&mut self, default: Stdio) -> io::Error { | |
39 | if self.saw_nul() { | |
60c5eb7d | 40 | return io::Error::new(io::ErrorKind::InvalidInput, "nul byte found in provided data"); |
476ff2be SL |
41 | } |
42 | ||
43 | match self.setup_io(default, true) { | |
44 | Ok((_, _)) => { | |
45 | // FIXME: This is tough because we don't support the exec syscalls | |
46 | unimplemented!(); | |
60c5eb7d | 47 | } |
476ff2be SL |
48 | Err(e) => e, |
49 | } | |
50 | } | |
51 | ||
60c5eb7d XL |
52 | unsafe fn do_exec( |
53 | &mut self, | |
54 | stdio: ChildPipes, | |
55 | maybe_envp: Option<&CStringArray>, | |
56 | ) -> io::Result<zx_handle_t> { | |
532ac7d7 | 57 | use crate::sys::process::zircon::*; |
476ff2be | 58 | |
ff7c6d11 | 59 | let envp = match maybe_envp { |
e1599b0c XL |
60 | // None means to clone the current environment, which is done in the |
61 | // flags below. | |
476ff2be | 62 | None => ptr::null(), |
e1599b0c | 63 | Some(envp) => envp.as_ptr(), |
476ff2be SL |
64 | }; |
65 | ||
e1599b0c XL |
66 | let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> { |
67 | if let Some(local_fd) = local_io.fd() { | |
68 | Ok(fdio_spawn_action_t { | |
69 | action: FDIO_SPAWN_ACTION_TRANSFER_FD, | |
70 | local_fd, | |
71 | target_fd, | |
72 | ..Default::default() | |
73 | }) | |
74 | } else { | |
75 | if let ChildStdio::Null = local_io { | |
76 | // acts as no-op | |
77 | return Ok(Default::default()); | |
78 | } | |
79 | ||
80 | let mut handle = ZX_HANDLE_INVALID; | |
81 | let status = fdio_fd_clone(target_fd, &mut handle); | |
82 | if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED { | |
83 | // This descriptor is closed; skip it rather than generating an | |
84 | // error. | |
85 | return Ok(Default::default()); | |
86 | } | |
87 | zx_cvt(status)?; | |
88 | ||
89 | let mut cloned_fd = 0; | |
90 | zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?; | |
91 | ||
92 | Ok(fdio_spawn_action_t { | |
93 | action: FDIO_SPAWN_ACTION_TRANSFER_FD, | |
94 | local_fd: cloned_fd as i32, | |
95 | target_fd, | |
96 | ..Default::default() | |
97 | }) | |
94b46f34 XL |
98 | } |
99 | }; | |
476ff2be SL |
100 | |
101 | // Clone stdin, stdout, and stderr | |
e1599b0c XL |
102 | let action1 = make_action(&stdio.stdin, 0)?; |
103 | let action2 = make_action(&stdio.stdout, 1)?; | |
104 | let action3 = make_action(&stdio.stderr, 2)?; | |
94b46f34 | 105 | let actions = [action1, action2, action3]; |
476ff2be | 106 | |
94b46f34 XL |
107 | // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc |
108 | // always consumes transferred file descriptors. | |
476ff2be SL |
109 | mem::forget(stdio); |
110 | ||
111 | for callback in self.get_closures().iter_mut() { | |
112 | callback()?; | |
113 | } | |
114 | ||
ea8adc8c | 115 | let mut process_handle: zx_handle_t = 0; |
94b46f34 | 116 | zx_cvt(fdio_spawn_etc( |
e1599b0c | 117 | ZX_HANDLE_INVALID, |
60c5eb7d XL |
118 | FDIO_SPAWN_CLONE_JOB |
119 | | FDIO_SPAWN_CLONE_LDSVC | |
120 | | FDIO_SPAWN_CLONE_NAMESPACE | |
121 | | FDIO_SPAWN_CLONE_ENVIRON, // this is ignored when envp is non-null | |
122 | self.get_program().as_ptr(), | |
123 | self.get_argv().as_ptr(), | |
124 | envp, | |
125 | actions.len() as size_t, | |
126 | actions.as_ptr(), | |
94b46f34 XL |
127 | &mut process_handle, |
128 | ptr::null_mut(), | |
129 | ))?; | |
8bb4bdeb XL |
130 | // FIXME: See if we want to do something with that err_msg |
131 | ||
132 | Ok(process_handle) | |
476ff2be SL |
133 | } |
134 | } | |
135 | ||
136 | //////////////////////////////////////////////////////////////////////////////// | |
137 | // Processes | |
138 | //////////////////////////////////////////////////////////////////////////////// | |
139 | ||
140 | pub struct Process { | |
476ff2be SL |
141 | handle: Handle, |
142 | } | |
143 | ||
144 | impl Process { | |
145 | pub fn id(&self) -> u32 { | |
146 | self.handle.raw() as u32 | |
147 | } | |
148 | ||
149 | pub fn kill(&mut self) -> io::Result<()> { | |
532ac7d7 | 150 | use crate::sys::process::zircon::*; |
476ff2be | 151 | |
60c5eb7d XL |
152 | unsafe { |
153 | zx_cvt(zx_task_kill(self.handle.raw()))?; | |
154 | } | |
476ff2be SL |
155 | |
156 | Ok(()) | |
157 | } | |
158 | ||
159 | pub fn wait(&mut self) -> io::Result<ExitStatus> { | |
532ac7d7 XL |
160 | use crate::default::Default; |
161 | use crate::sys::process::zircon::*; | |
476ff2be | 162 | |
ea8adc8c XL |
163 | let mut proc_info: zx_info_process_t = Default::default(); |
164 | let mut actual: size_t = 0; | |
165 | let mut avail: size_t = 0; | |
476ff2be SL |
166 | |
167 | unsafe { | |
60c5eb7d XL |
168 | zx_cvt(zx_object_wait_one( |
169 | self.handle.raw(), | |
170 | ZX_TASK_TERMINATED, | |
171 | ZX_TIME_INFINITE, | |
172 | ptr::null_mut(), | |
173 | ))?; | |
174 | zx_cvt(zx_object_get_info( | |
175 | self.handle.raw(), | |
176 | ZX_INFO_PROCESS, | |
177 | &mut proc_info as *mut _ as *mut libc::c_void, | |
178 | mem::size_of::<zx_info_process_t>(), | |
179 | &mut actual, | |
180 | &mut avail, | |
181 | ))?; | |
476ff2be SL |
182 | } |
183 | if actual != 1 { | |
60c5eb7d XL |
184 | return Err(io::Error::new( |
185 | io::ErrorKind::InvalidData, | |
186 | "Failed to get exit status of process", | |
187 | )); | |
476ff2be | 188 | } |
e74abb32 | 189 | Ok(ExitStatus(proc_info.return_code)) |
476ff2be | 190 | } |
32a655c1 | 191 | |
8bb4bdeb | 192 | pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { |
532ac7d7 XL |
193 | use crate::default::Default; |
194 | use crate::sys::process::zircon::*; | |
32a655c1 | 195 | |
ea8adc8c XL |
196 | let mut proc_info: zx_info_process_t = Default::default(); |
197 | let mut actual: size_t = 0; | |
198 | let mut avail: size_t = 0; | |
32a655c1 SL |
199 | |
200 | unsafe { | |
60c5eb7d XL |
201 | let status = |
202 | zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut()); | |
32a655c1 | 203 | match status { |
60c5eb7d | 204 | 0 => {} // Success |
32a655c1 | 205 | x if x == ERR_TIMED_OUT => { |
8bb4bdeb | 206 | return Ok(None); |
60c5eb7d XL |
207 | } |
208 | _ => { | |
209 | panic!("Failed to wait on process handle: {}", status); | |
210 | } | |
32a655c1 | 211 | } |
60c5eb7d XL |
212 | zx_cvt(zx_object_get_info( |
213 | self.handle.raw(), | |
214 | ZX_INFO_PROCESS, | |
215 | &mut proc_info as *mut _ as *mut libc::c_void, | |
216 | mem::size_of::<zx_info_process_t>(), | |
217 | &mut actual, | |
218 | &mut avail, | |
219 | ))?; | |
32a655c1 SL |
220 | } |
221 | if actual != 1 { | |
60c5eb7d XL |
222 | return Err(io::Error::new( |
223 | io::ErrorKind::InvalidData, | |
224 | "Failed to get exit status of process", | |
225 | )); | |
32a655c1 | 226 | } |
e74abb32 XL |
227 | Ok(Some(ExitStatus(proc_info.return_code))) |
228 | } | |
229 | } | |
230 | ||
231 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | |
232 | pub struct ExitStatus(i64); | |
233 | ||
234 | impl ExitStatus { | |
235 | pub fn success(&self) -> bool { | |
236 | self.code() == Some(0) | |
237 | } | |
238 | ||
239 | pub fn code(&self) -> Option<i32> { | |
240 | // FIXME: support extracting return code as an i64 | |
241 | self.0.try_into().ok() | |
242 | } | |
243 | ||
244 | pub fn signal(&self) -> Option<i32> { | |
245 | None | |
246 | } | |
247 | } | |
248 | ||
249 | impl From<c_int> for ExitStatus { | |
250 | fn from(a: c_int) -> ExitStatus { | |
251 | ExitStatus(a as i64) | |
252 | } | |
253 | } | |
254 | ||
255 | impl fmt::Display for ExitStatus { | |
256 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
257 | write!(f, "exit code: {}", self.0) | |
476ff2be SL |
258 | } |
259 | } |