1use std::{
2 any::Any,
3 io::{Read, Result},
4 process::{Child, ChildStderr, ChildStdin, ChildStdout, Command, ExitStatus, Output},
5};
6
7#[cfg(windows)]
8use std::os::windows::io::{AsHandle, BorrowedHandle};
9
10#[cfg(unix)]
11use nix::{
12 sys::signal::{Signal, kill},
13 unistd::Pid,
14};
15
16crate::generic_wrap::Wrap!(Command, Child, ChildWrapper, |child| child);
17
18pub trait ChildWrapper: Any + std::fmt::Debug + Send + Sync {
68 fn inner(&self) -> &dyn ChildWrapper;
70
71 fn inner_mut(&mut self) -> &mut dyn ChildWrapper;
73
74 fn into_inner(self: Box<Self>) -> Box<dyn ChildWrapper>;
80
81 #[cfg(windows)]
91 fn process_handle(&self) -> Option<BorrowedHandle<'_>> {
92 None
93 }
94
95 fn try_clone(&self) -> Option<Box<dyn ChildWrapper>> {
100 None
101 }
102
103 fn stdin(&mut self) -> &mut Option<ChildStdin> {
107 self.inner_mut().stdin()
108 }
109
110 fn stdout(&mut self) -> &mut Option<ChildStdout> {
114 self.inner_mut().stdout()
115 }
116
117 fn stderr(&mut self) -> &mut Option<ChildStderr> {
121 self.inner_mut().stderr()
122 }
123
124 fn id(&self) -> u32 {
129 self.inner().id()
130 }
131
132 fn kill(&mut self) -> Result<()> {
138 self.start_kill()?;
139 self.wait()?;
140 Ok(())
141 }
142
143 fn start_kill(&mut self) -> Result<()> {
153 self.inner_mut().start_kill()
154 }
155
156 fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
163 self.inner_mut().try_wait()
164 }
165
166 fn wait(&mut self) -> Result<ExitStatus> {
173 self.inner_mut().wait()
174 }
175
176 fn wait_with_output(mut self: Box<Self>) -> Result<Output>
186 where
187 Self: 'static,
188 {
189 drop(self.stdin().take());
190
191 let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
192 match (self.stdout().take(), self.stderr().take()) {
193 (None, None) => {}
194 (Some(mut out), None) => {
195 let res = out.read_to_end(&mut stdout);
196 res.unwrap();
197 }
198 (None, Some(mut err)) => {
199 let res = err.read_to_end(&mut stderr);
200 res.unwrap();
201 }
202 (Some(out), Some(err)) => {
203 let res = read2(out, &mut stdout, err, &mut stderr);
204 res.unwrap();
205 }
206 }
207
208 let status = self.wait()?;
209 Ok(Output {
210 status,
211 stdout,
212 stderr,
213 })
214 }
215
216 #[cfg(unix)]
222 fn signal(&self, sig: i32) -> Result<()> {
223 self.inner().signal(sig)
224 }
225}
226
227impl ChildWrapper for Child {
228 fn inner(&self) -> &dyn ChildWrapper {
229 self
230 }
231 fn inner_mut(&mut self) -> &mut dyn ChildWrapper {
232 self
233 }
234 fn into_inner(self: Box<Self>) -> Box<dyn ChildWrapper> {
235 self
236 }
237 #[cfg(windows)]
238 fn process_handle(&self) -> Option<BorrowedHandle<'_>> {
239 Some(self.as_handle())
240 }
241 fn stdin(&mut self) -> &mut Option<ChildStdin> {
242 &mut self.stdin
243 }
244 fn stdout(&mut self) -> &mut Option<ChildStdout> {
245 &mut self.stdout
246 }
247 fn stderr(&mut self) -> &mut Option<ChildStderr> {
248 &mut self.stderr
249 }
250 fn id(&self) -> u32 {
251 Child::id(self)
252 }
253 fn start_kill(&mut self) -> Result<()> {
254 #[cfg(unix)]
255 {
256 self.signal(Signal::SIGKILL as _)
257 }
258
259 #[cfg(not(unix))]
260 {
261 Child::kill(self)
262 }
263 }
264 fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
265 Child::try_wait(self)
266 }
267 fn wait(&mut self) -> Result<ExitStatus> {
268 Child::wait(self)
269 }
270 #[cfg(unix)]
271 fn signal(&self, sig: i32) -> Result<()> {
272 kill(
273 Pid::from_raw(i32::try_from(self.id()).map_err(std::io::Error::other)?),
274 Signal::try_from(sig)?,
275 )
276 .map_err(std::io::Error::from)
277 }
278}
279
280fn same_child(left: &dyn ChildWrapper, right: &dyn ChildWrapper) -> bool {
281 std::ptr::addr_eq(left, right) && left.type_id() == right.type_id()
282}
283
284impl dyn ChildWrapper + '_ {
285 fn downcast_ref<T: 'static>(&self) -> Option<&T> {
286 (self as &dyn Any).downcast_ref()
287 }
288
289 fn is_raw_child(&self) -> bool {
290 self.downcast_ref::<Child>().is_some()
291 }
292
293 pub fn try_inner_child(&self) -> Option<&Child> {
297 let mut inner = self;
298 loop {
299 if let Some(child) = inner.downcast_ref::<Child>() {
300 return Some(child);
301 }
302
303 let next = inner.inner();
304 if same_child(inner, next) {
305 return None;
306 }
307 inner = next;
308 }
309 }
310
311 pub unsafe fn try_inner_child_mut(&mut self) -> Option<&mut Child> {
320 let mut inner = self;
321 loop {
322 if inner.is_raw_child() {
323 return (inner as &mut dyn Any).downcast_mut();
324 }
325
326 let inner_type = (&*inner as &dyn Any).type_id();
327 let inner_ptr = std::ptr::from_mut(inner);
328 let next = inner.inner_mut();
329 if std::ptr::addr_eq(inner_ptr, std::ptr::from_mut(next))
330 && inner_type == (&*next as &dyn Any).type_id()
331 {
332 return None;
333 }
334 inner = next;
335 }
336 }
337
338 pub unsafe fn try_into_inner_child(self: Box<Self>) -> std::result::Result<Child, Box<Self>> {
349 let mut inner = self;
350 loop {
351 if inner.is_raw_child() {
352 return match (inner as Box<dyn Any>).downcast::<Child>() {
353 Ok(child) => Ok(*child),
354 Err(_) => unreachable!("native child type was checked before downcasting"),
355 };
356 }
357
358 let terminal = {
359 let next = inner.inner();
360 same_child(inner.as_ref(), next)
361 };
362 if terminal {
363 return Err(inner);
364 }
365 inner = inner.into_inner();
366 }
367 }
368}
369
370#[cfg(unix)]
371fn read2(
372 mut out_r: ChildStdout,
373 out_v: &mut Vec<u8>,
374 mut err_r: ChildStderr,
375 err_v: &mut Vec<u8>,
376) -> Result<()> {
377 use nix::{
378 errno::Errno,
379 libc,
380 poll::{PollFd, PollFlags, PollTimeout, poll},
381 };
382 use std::{
383 io::Error,
384 os::fd::{AsRawFd, BorrowedFd},
385 };
386
387 let out_fd = out_r.as_raw_fd();
388 let err_fd = err_r.as_raw_fd();
389 let out_bfd = unsafe { BorrowedFd::borrow_raw(out_fd) };
391 let err_bfd = unsafe { BorrowedFd::borrow_raw(err_fd) };
392
393 set_nonblocking(out_bfd, true)?;
394 set_nonblocking(err_bfd, true)?;
395
396 let mut fds = [
397 PollFd::new(out_bfd, PollFlags::POLLIN),
398 PollFd::new(err_bfd, PollFlags::POLLIN),
399 ];
400
401 loop {
402 poll(&mut fds, PollTimeout::NONE)?;
403
404 if fds[0].revents().is_some() && read(&mut out_r, out_v)? {
405 set_nonblocking(err_bfd, false)?;
406 return err_r.read_to_end(err_v).map(drop);
407 }
408 if fds[1].revents().is_some() && read(&mut err_r, err_v)? {
409 set_nonblocking(out_bfd, false)?;
410 return out_r.read_to_end(out_v).map(drop);
411 }
412 }
413
414 fn read(r: &mut impl Read, dst: &mut Vec<u8>) -> Result<bool> {
415 match r.read_to_end(dst) {
416 Ok(_) => Ok(true),
417 Err(e) => {
418 if e.raw_os_error() == Some(libc::EWOULDBLOCK)
419 || e.raw_os_error() == Some(libc::EAGAIN)
420 {
421 Ok(false)
422 } else {
423 Err(e)
424 }
425 }
426 }
427 }
428
429 #[cfg(target_os = "linux")]
430 fn set_nonblocking(fd: BorrowedFd, nonblocking: bool) -> Result<()> {
431 let v = nonblocking as libc::c_int;
432 let res = unsafe { libc::ioctl(fd.as_raw_fd(), libc::FIONBIO, &v) };
433
434 Errno::result(res).map_err(Error::from).map(drop)
435 }
436
437 #[cfg(not(target_os = "linux"))]
438 fn set_nonblocking(fd: BorrowedFd, nonblocking: bool) -> Result<()> {
439 use nix::fcntl::{FcntlArg, OFlag, fcntl};
440
441 let mut flags = OFlag::from_bits_truncate(fcntl(fd, FcntlArg::F_GETFL)?);
442 flags.set(OFlag::O_NONBLOCK, nonblocking);
443
444 fcntl(fd, FcntlArg::F_SETFL(flags))
445 .map_err(Error::from)
446 .map(drop)
447 }
448}
449
450#[cfg(not(unix))]
453fn read2(
454 mut out_r: ChildStdout,
455 out_v: &mut Vec<u8>,
456 mut err_r: ChildStderr,
457 err_v: &mut Vec<u8>,
458) -> Result<()> {
459 out_r.read_to_end(out_v)?;
460 err_r.read_to_end(err_v)?;
461 Ok(())
462}
463
464const _: () = {
465 const fn assert_sync<T: ?Sized + Sync>() {}
466 assert_sync::<dyn ChildWrapper>();
467};