1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::fs::File;
15 use std::future::Future;
16 use std::io::IoSlice;
17 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd};
18 use std::pin::Pin;
19 use std::process::{Child as StdChild, ExitStatus, Stdio};
20 use std::task::{Context, Poll};
21 use std::{fmt, io};
22 
23 use super::pipe::Pipe;
24 use crate::io::{AsyncRead, AsyncWrite, ReadBuf};
25 use crate::net::AsyncSource;
26 use crate::signal::{signal, Signal, SignalKind};
27 
28 pub(crate) struct Child {
29     std: Option<StdChild>,
30     signal: Signal,
31 }
32 
33 impl Child {
new(child: StdChild) -> io::Result<Self>34     pub(crate) fn new(child: StdChild) -> io::Result<Self> {
35         Ok(Child {
36             std: Some(child),
37             signal: signal(SignalKind::child())?,
38         })
39     }
40 
id(&self) -> u3241     pub(crate) fn id(&self) -> u32 {
42         // std is always Some before drop.
43         self.std.as_ref().unwrap().id()
44     }
45 
kill(&mut self) -> io::Result<()>46     pub(crate) fn kill(&mut self) -> io::Result<()> {
47         // std is always Some before drop.
48         self.std.as_mut().unwrap().kill()
49     }
50 
try_wait(&mut self) -> io::Result<Option<ExitStatus>>51     pub(crate) fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
52         // std is always Some before drop.
53         self.std.as_mut().unwrap().try_wait()
54     }
55 }
56 
57 impl fmt::Debug for Child {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result58     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59         self.std.fmt(f)
60     }
61 }
62 
63 impl Future for Child {
64     type Output = io::Result<ExitStatus>;
65 
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>66     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
67         loop {
68             let signal_pending = self.signal.poll_recv(cx).is_pending();
69 
70             if let Some(status) = self.try_wait()? {
71                 return Poll::Ready(Ok(status));
72             }
73 
74             if signal_pending {
75                 return Poll::Pending;
76             }
77         }
78     }
79 }
80 
81 impl Drop for Child {
drop(&mut self)82     fn drop(&mut self) {
83         if let Ok(Some(_)) = self.try_wait() {
84             return;
85         }
86         // std is always Some before drop.
87         let std = self.std.take().unwrap();
88         crate::process::GlobalZombieChild::get_instance().push(std);
89     }
90 }
91 
stdio<T: IntoRawFd>(io: T) -> io::Result<ChildStdio>92 pub(crate) fn stdio<T: IntoRawFd>(io: T) -> io::Result<ChildStdio> {
93     let mut pipe = Pipe::from(io);
94     set_nonblock(&mut pipe, true)?;
95 
96     AsyncSource::new(pipe, None).map(|inner| ChildStdio { inner })
97 }
98 
to_blocking_file(io: ChildStdio) -> io::Result<File>99 fn to_blocking_file(io: ChildStdio) -> io::Result<File> {
100     let mut file = io.inner.io_take()?.fd;
101     set_nonblock(&mut file, false)?;
102     Ok(file)
103 }
104 
set_nonblock<T: AsRawFd>(fd: &mut T, block: bool) -> io::Result<()>105 fn set_nonblock<T: AsRawFd>(fd: &mut T, block: bool) -> io::Result<()> {
106     unsafe {
107         let fd = fd.as_raw_fd();
108         let mut flags = libc::fcntl(fd, libc::F_GETFL);
109         if flags == -1 {
110             return Err(io::Error::last_os_error());
111         }
112         if block {
113             flags |= libc::O_NONBLOCK;
114         } else {
115             flags &= !libc::O_NONBLOCK;
116         }
117         match libc::fcntl(fd, libc::F_SETFL, flags) {
118             -1 => Err(io::Error::last_os_error()),
119             _ => Ok(()),
120         }
121     }
122 }
123 
to_stdio(io: ChildStdio) -> io::Result<Stdio>124 pub(crate) fn to_stdio(io: ChildStdio) -> io::Result<Stdio> {
125     to_blocking_file(io).map(Stdio::from)
126 }
127 
128 #[derive(Debug)]
129 pub(crate) struct ChildStdio {
130     inner: AsyncSource<Pipe>,
131 }
132 
133 impl ChildStdio {
into_owned_fd(self) -> io::Result<OwnedFd>134     pub(crate) fn into_owned_fd(self) -> io::Result<OwnedFd> {
135         to_blocking_file(self).map(OwnedFd::from)
136     }
137 }
138 
139 impl AsyncWrite for ChildStdio {
poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>140     fn poll_write(
141         self: Pin<&mut Self>,
142         cx: &mut Context<'_>,
143         buf: &[u8],
144     ) -> Poll<io::Result<usize>> {
145         self.inner.poll_write(cx, buf)
146     }
147 
poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>], ) -> Poll<io::Result<usize>>148     fn poll_write_vectored(
149         self: Pin<&mut Self>,
150         cx: &mut Context<'_>,
151         bufs: &[IoSlice<'_>],
152     ) -> Poll<io::Result<usize>> {
153         self.inner.poll_write_vectored(cx, bufs)
154     }
155 
is_write_vectored(&self) -> bool156     fn is_write_vectored(&self) -> bool {
157         true
158     }
159 
poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>160     fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
161         Poll::Ready(Ok(()))
162     }
163 
poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>164     fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
165         Poll::Ready(Ok(()))
166     }
167 }
168 
169 impl AsyncRead for ChildStdio {
poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>170     fn poll_read(
171         self: Pin<&mut Self>,
172         cx: &mut Context<'_>,
173         buf: &mut ReadBuf<'_>,
174     ) -> Poll<io::Result<()>> {
175         self.inner.poll_read(cx, buf)
176     }
177 }
178 
179 impl AsRawFd for ChildStdio {
as_raw_fd(&self) -> RawFd180     fn as_raw_fd(&self) -> RawFd {
181         AsRawFd::as_raw_fd(&*(self.inner))
182     }
183 }
184 
185 impl AsFd for ChildStdio {
as_fd(&self) -> BorrowedFd<'_>186     fn as_fd(&self) -> BorrowedFd<'_> {
187         unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
188     }
189 }
190