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