1use core::pin::Pin;
10use core::task::Context;
11use core::task::Poll;
12use std::io;
13use std::os::fd::OwnedFd;
14use std::os::unix::io::AsRawFd;
15use std::os::unix::io::FromRawFd;
16use std::os::unix::io::IntoRawFd;
17
18use syscalls::Errno;
19use tokio::io::AsyncRead;
20use tokio::io::AsyncWrite;
21use tokio::io::ReadBuf;
22
23use super::fd::AsyncFd;
24use super::fd::Fd;
25use super::fd::pipe;
26
27#[derive(Debug)]
35pub struct Stdio(InnerStdio);
36
37#[derive(Debug)]
49pub struct ChildStdin(AsyncFd);
50
51#[derive(Debug)]
62pub struct ChildStdout(AsyncFd);
63
64#[derive(Debug)]
75pub struct ChildStderr(AsyncFd);
76
77#[derive(Debug)]
78enum InnerStdio {
79 Inherit,
80 Null,
81 Piped,
82 File(Fd),
83}
84
85impl Default for Stdio {
86 fn default() -> Self {
87 Self(InnerStdio::Inherit)
88 }
89}
90
91impl Stdio {
92 pub fn piped() -> Self {
94 Self(InnerStdio::Piped)
95 }
96
97 pub fn inherit() -> Self {
99 Self(InnerStdio::Inherit)
100 }
101
102 pub fn null() -> Self {
105 Self(InnerStdio::Null)
106 }
107
108 pub(super) fn pipes(&self, readable: bool) -> Result<(Option<Fd>, Option<Fd>), Errno> {
115 match &self.0 {
116 InnerStdio::Inherit => Ok((None, None)),
117 InnerStdio::Null => Ok((None, Some(Fd::null(readable)?))),
118 InnerStdio::Piped => {
119 let (reader, writer) = pipe()?;
120 let (parent, child) = if readable {
121 (writer, reader)
122 } else {
123 (reader, writer)
124 };
125 Ok((Some(parent), Some(child)))
126 }
127 InnerStdio::File(file) => Ok((None, Some(file.dup()?))),
128 }
129 }
130}
131
132impl<T: IntoRawFd> From<T> for Stdio {
133 fn from(f: T) -> Self {
134 Self(InnerStdio::File(Fd::new(f.into_raw_fd())))
135 }
136}
137
138impl From<Stdio> for std::process::Stdio {
139 fn from(stdio: Stdio) -> Self {
140 match stdio.0 {
141 InnerStdio::Inherit => Self::inherit(),
142 InnerStdio::Null => Self::null(),
143 InnerStdio::Piped => Self::piped(),
144 InnerStdio::File(fd) => Self::from(std::fs::File::from(fd)),
145 }
146 }
147}
148
149impl ChildStdin {
150 pub(super) fn new(fd: Fd) -> Result<Self, Errno> {
151 AsyncFd::writable(fd).map(Self)
152 }
153}
154
155impl ChildStdout {
156 pub(super) fn new(fd: Fd) -> Result<Self, Errno> {
157 AsyncFd::readable(fd).map(Self)
158 }
159}
160
161impl ChildStderr {
162 pub(super) fn new(fd: Fd) -> Result<Self, Errno> {
163 AsyncFd::readable(fd).map(Self)
164 }
165}
166
167impl AsyncWrite for ChildStdin {
168 fn poll_write(
169 mut self: Pin<&mut Self>,
170 cx: &mut Context<'_>,
171 buf: &[u8],
172 ) -> Poll<tokio::io::Result<usize>> {
173 Pin::new(&mut self.0).poll_write(cx, buf)
174 }
175
176 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
177 Pin::new(&mut self.0).poll_flush(cx)
178 }
179
180 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
181 Pin::new(&mut self.0).poll_shutdown(cx)
182 }
183}
184
185impl AsyncRead for ChildStdout {
186 fn poll_read(
187 mut self: Pin<&mut Self>,
188 cx: &mut Context,
189 buf: &mut ReadBuf,
190 ) -> Poll<tokio::io::Result<()>> {
191 Pin::new(&mut self.0).poll_read(cx, buf)
192 }
193}
194
195impl AsyncRead for ChildStderr {
196 fn poll_read(
197 mut self: Pin<&mut Self>,
198 cx: &mut Context,
199 buf: &mut ReadBuf,
200 ) -> Poll<tokio::io::Result<()>> {
201 Pin::new(&mut self.0).poll_read(cx, buf)
202 }
203}
204
205impl FromRawFd for ChildStdin {
206 unsafe fn from_raw_fd(fd: i32) -> Self {
207 Self::new(Fd::new(fd)).unwrap()
208 }
209}
210
211impl From<OwnedFd> for ChildStdin {
212 fn from(fd: OwnedFd) -> Self {
213 Self::new(fd.into()).unwrap()
214 }
215}
216
217impl FromRawFd for ChildStdout {
218 unsafe fn from_raw_fd(fd: i32) -> Self {
219 Self::new(Fd::new(fd)).unwrap()
220 }
221}
222
223impl From<OwnedFd> for ChildStdout {
224 fn from(fd: OwnedFd) -> Self {
225 Self::new(fd.into()).unwrap()
226 }
227}
228
229impl FromRawFd for ChildStderr {
230 unsafe fn from_raw_fd(fd: i32) -> Self {
231 Self::new(Fd::new(fd)).unwrap()
232 }
233}
234
235impl From<OwnedFd> for ChildStderr {
236 fn from(fd: OwnedFd) -> Self {
237 Self::new(fd.into()).unwrap()
238 }
239}
240
241impl From<tokio::process::ChildStdin> for ChildStdin {
242 fn from(io: tokio::process::ChildStdin) -> Self {
243 let fd = io.as_raw_fd();
244 let fd = unsafe { libc::dup(fd) };
245 drop(io);
246 unsafe { Self::from_raw_fd(fd) }
247 }
248}
249
250impl From<tokio::process::ChildStdout> for ChildStdout {
251 fn from(io: tokio::process::ChildStdout) -> Self {
252 let fd = io.as_raw_fd();
253 let fd = unsafe { libc::dup(fd) };
254 drop(io);
255 unsafe { Self::from_raw_fd(fd) }
256 }
257}
258
259impl From<tokio::process::ChildStderr> for ChildStderr {
260 fn from(io: tokio::process::ChildStderr) -> Self {
261 let fd = io.as_raw_fd();
262 let fd = unsafe { libc::dup(fd) };
263 drop(io);
264 unsafe { Self::from_raw_fd(fd) }
265 }
266}