memfd_exec/
child.rs

1use std::fmt::{Debug, Formatter, Result as FmtResult};
2use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Read, Result, Write};
3
4use crate::anon_pipe::{read2, AnonPipe};
5use crate::output::Output;
6use crate::process::{ExitStatus, Process};
7use crate::stdio::StdioPipes;
8
9/// A child process created from a `MemFdExecutable` with handles to input and output streams
10pub struct Child {
11    handle: Process,
12    /// The input stream to the child process
13    pub stdin: Option<ChildStdin>,
14    /// The output stream from the child process
15    pub stdout: Option<ChildStdout>,
16    /// The error stream from the child process
17    pub stderr: Option<ChildStderr>,
18}
19
20impl Child {
21    pub fn new(handle: Process, stdio: StdioPipes) -> Self {
22        Self {
23            handle,
24            stdin: stdio.stdin.map(ChildStdin),
25            stdout: stdio.stdout.map(ChildStdout),
26            stderr: stdio.stderr.map(ChildStderr),
27        }
28    }
29
30    /// Kill the child process
31    pub fn kill(&mut self) -> Result<()> {
32        self.handle.kill()
33    }
34
35    /// Return the id of the child process, probably a PID
36    pub fn id(&self) -> u32 {
37        self.handle.id()
38    }
39
40    /// Wait for the child process to exit, returning the exit status code
41    pub fn wait(&mut self) -> Result<ExitStatus> {
42        drop(self.stdin.take());
43        self.handle.wait()
44    }
45
46    /// Try and wait for the child process to exit, returning the exit status code if it has
47    pub fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
48        self.handle.try_wait()
49    }
50
51    /// Wait for the child process to exit, returning the exit status code and the output
52    /// streams
53    pub fn wait_with_output(mut self) -> Result<Output> {
54        drop(self.stdin.take());
55
56        let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
57        match (self.stdout.take(), self.stderr.take()) {
58            (None, None) => {}
59            (Some(mut out), None) => {
60                out.read_to_end(&mut stdout)?;
61            }
62            (None, Some(mut err)) => {
63                err.read_to_end(&mut stderr)?;
64            }
65            (Some(out), Some(err)) => {
66                read2(out.0, &mut stdout, err.0, &mut stderr)?;
67            }
68        }
69
70        Ok(Output {
71            status: self.wait()?,
72            stdout,
73            stderr,
74        })
75    }
76}
77
78/// A handle to a child process’s standard input (stdin).
79pub struct ChildStdin(AnonPipe);
80
81impl std::os::fd::AsRawFd for ChildStdin {
82    #[inline]
83    fn as_raw_fd(&self) -> std::os::fd::RawFd {
84        self.0.as_raw_fd()
85    }
86}
87
88impl Write for ChildStdin {
89    fn write(&mut self, buf: &[u8]) -> Result<usize> {
90        (&*self).write(buf)
91    }
92
93    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
94        (&*self).write_vectored(bufs)
95    }
96
97    fn flush(&mut self) -> Result<()> {
98        (&*self).flush()
99    }
100
101    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
102        (&*self).write_all(buf)
103    }
104}
105
106impl Write for &ChildStdin {
107    fn write(&mut self, buf: &[u8]) -> Result<usize> {
108        self.0.write(buf)
109    }
110
111    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
112        self.0.write_vectored(bufs)
113    }
114
115    fn flush(&mut self) -> Result<()> {
116        Ok(())
117    }
118
119    fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
120        while !buf.is_empty() {
121            match self.write(buf) {
122                Ok(0) => {
123                    return Err(Error::new(
124                        ErrorKind::WriteZero,
125                        "failed to write whole buffer",
126                    ))
127                }
128                Ok(n) => buf = &buf[n..],
129                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
130                Err(e) => return Err(e),
131            }
132        }
133        Ok(())
134    }
135}
136
137impl Debug for ChildStdin {
138    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
139        f.debug_struct("ChildStdin").finish_non_exhaustive()
140    }
141}
142
143/// A handle to a child process’s standard output (stdout).
144pub struct ChildStdout(AnonPipe);
145
146impl std::os::fd::AsRawFd for ChildStdout {
147    #[inline]
148    fn as_raw_fd(&self) -> std::os::fd::RawFd {
149        self.0.as_raw_fd()
150    }
151}
152
153impl Write for ChildStdout {
154    fn write(&mut self, buf: &[u8]) -> Result<usize> {
155        (&*self).write(buf)
156    }
157
158    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
159        (&*self).write_vectored(bufs)
160    }
161
162    fn flush(&mut self) -> Result<()> {
163        (&*self).flush()
164    }
165
166    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
167        (&*self).write_all(buf)
168    }
169}
170
171impl Write for &ChildStdout {
172    fn write(&mut self, buf: &[u8]) -> Result<usize> {
173        self.0.write(buf)
174    }
175
176    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
177        self.0.write_vectored(bufs)
178    }
179
180    fn flush(&mut self) -> Result<()> {
181        Ok(())
182    }
183
184    fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
185        while !buf.is_empty() {
186            match self.write(buf) {
187                Ok(0) => {
188                    return Err(Error::new(
189                        ErrorKind::WriteZero,
190                        "failed to write whole buffer",
191                    ))
192                }
193                Ok(n) => buf = &buf[n..],
194                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
195                Err(e) => return Err(e),
196            }
197        }
198        Ok(())
199    }
200}
201
202impl Read for ChildStdout {
203    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
204        (&*self).read(buf)
205    }
206
207    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
208        (&*self).read_vectored(bufs)
209    }
210
211    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
212        (&*self).read_to_end(buf)
213    }
214}
215
216impl Read for &ChildStdout {
217    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
218        self.0.read(buf)
219    }
220
221    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
222        self.0.read_vectored(bufs)
223    }
224
225    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
226        self.0.read_to_end(buf)
227    }
228}
229
230impl Debug for ChildStdout {
231    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
232        f.debug_struct("ChildStdout").finish_non_exhaustive()
233    }
234}
235
236/// A handle to a child process’s stderr.
237pub struct ChildStderr(AnonPipe);
238
239impl std::os::fd::AsRawFd for ChildStderr {
240    #[inline]
241    fn as_raw_fd(&self) -> std::os::fd::RawFd {
242        self.0.as_raw_fd()
243    }
244}
245
246impl Write for ChildStderr {
247    fn write(&mut self, buf: &[u8]) -> Result<usize> {
248        (&*self).write(buf)
249    }
250
251    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
252        (&*self).write_vectored(bufs)
253    }
254
255    fn flush(&mut self) -> Result<()> {
256        (&*self).flush()
257    }
258
259    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
260        (&*self).write_all(buf)
261    }
262}
263
264impl Write for &ChildStderr {
265    fn write(&mut self, buf: &[u8]) -> Result<usize> {
266        self.0.write(buf)
267    }
268
269    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
270        self.0.write_vectored(bufs)
271    }
272
273    fn flush(&mut self) -> Result<()> {
274        Ok(())
275    }
276
277    fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
278        while !buf.is_empty() {
279            match self.write(buf) {
280                Ok(0) => {
281                    return Err(Error::new(
282                        ErrorKind::WriteZero,
283                        "failed to write whole buffer",
284                    ))
285                }
286                Ok(n) => buf = &buf[n..],
287                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
288                Err(e) => return Err(e),
289            }
290        }
291        Ok(())
292    }
293}
294
295impl Read for ChildStderr {
296    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
297        (&*self).read(buf)
298    }
299
300    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
301        (&*self).read_vectored(bufs)
302    }
303
304    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
305        (&*self).read_to_end(buf)
306    }
307}
308
309impl Read for &ChildStderr {
310    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
311        self.0.read(buf)
312    }
313
314    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
315        self.0.read_vectored(bufs)
316    }
317
318    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
319        self.0.read_to_end(buf)
320    }
321}
322
323impl Debug for ChildStderr {
324    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
325        f.debug_struct("ChildStderr").finish_non_exhaustive()
326    }
327}
328
329impl Debug for Child {
330    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
331        f.debug_struct("Child")
332            .field("stdin", &self.stdin)
333            .field("stdout", &self.stdout)
334            .field("stderr", &self.stderr)
335            .finish_non_exhaustive()
336    }
337}