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::fmt::Debug;
15 use std::io;
16 use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
17 use std::pin::Pin;
18 use std::process::Stdio;
19 use std::sync::Arc;
20 use std::task::{Context, Poll};
21 
22 use crate::io::{AsyncRead, AsyncWrite, ReadBuf};
23 use crate::net::AsyncSource;
24 
25 /// Async `Pty` which implement `AsyncRead` and `AsyncWrite`
26 #[derive(Debug)]
27 pub struct Pty(AsyncSource<super::sys::PtyInner>);
28 
29 impl Pty {
30     /// Creates a new async `Pty`
31     ///
32     /// # Example
33     ///
34     /// ```no_run
35     /// use ylong_runtime::process::pty_process::Pty;
36     ///
37     /// let _pty = Pty::new().expect("create Pty fail!");
38     /// ```
new() -> io::Result<Self>39     pub fn new() -> io::Result<Self> {
40         let pty = super::sys::PtyInner::open()?;
41         pty.set_nonblocking()?;
42         let source = AsyncSource::new(pty, None)?;
43         Ok(Pty(source))
44     }
45 
46     /// Changes the size of the terminal with `Pty`
47     ///
48     /// # Example
49     ///
50     /// ```no_run
51     /// use ylong_runtime::process::pty_process::Pty;
52     ///
53     /// let pty = Pty::new().expect("create Pty fail!");
54     /// pty.resize(24, 80, 0, 0).expect("resize set fail!");
55     /// ```
resize( &self, ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, ) -> io::Result<()>56     pub fn resize(
57         &self,
58         ws_row: u16,
59         ws_col: u16,
60         ws_xpixel: u16,
61         ws_ypixel: u16,
62     ) -> io::Result<()> {
63         (*self.0).set_size(ws_row, ws_col, ws_xpixel, ws_ypixel)
64     }
65 
66     /// Open a fd for the other end of the `Pty`, which should be attached to
67     /// the child process running in it.
68     ///
69     /// # Example
70     ///
71     /// ```no_run
72     /// use ylong_runtime::process::pty_process::Pty;
73     ///
74     /// let pty = Pty::new().expect("create Pty fail!");
75     /// let pts = pty.pts().expect("get pts fail!");
76     /// ```
pts(&self) -> io::Result<Pts>77     pub fn pts(&self) -> io::Result<Pts> {
78         const PATH_BUF_SIZE: usize = 256;
79         (*self.0).pts(PATH_BUF_SIZE).map(Pts::new)
80     }
81 
82     /// Splits a `Pty` into a read half and a write half with reference,
83     /// which can be used to read and write the stream concurrently.
84     ///
85     /// # Example
86     ///
87     /// ```no_run
88     /// use std::io;
89     ///
90     /// use ylong_runtime::process::pty_process::Pty;
91     ///
92     /// async fn io_func() -> io::Result<()> {
93     ///     let mut pty = Pty::new().expect("create Pty fail!");
94     ///     let (read_pty, write_pty) = pty.split();
95     ///     Ok(())
96     /// }
97     /// ```
split(&mut self) -> (BorrowReadPty, BorrowWritePty)98     pub fn split(&mut self) -> (BorrowReadPty, BorrowWritePty) {
99         let read = BorrowReadPty(self);
100         let write = BorrowWritePty(self);
101         (read, write)
102     }
103 
104     /// Splits a `Pty` into a read half and a write half,
105     /// which can be used to read and write the stream concurrently.
106     ///
107     /// # Example
108     ///
109     /// ```no_run
110     /// use std::io;
111     ///
112     /// use ylong_runtime::process::pty_process::Pty;
113     ///
114     /// async fn io_func() -> io::Result<()> {
115     ///     let mut pty = Pty::new().expect("create Pty fail!");
116     ///     let (read_pty, write_pty) = pty.into_split();
117     ///     Ok(())
118     /// }
119     /// ```
into_split(self) -> (SplitReadPty, SplitWritePty)120     pub fn into_split(self) -> (SplitReadPty, SplitWritePty) {
121         let arc = Arc::new(self);
122         let read = SplitReadPty(Arc::clone(&arc));
123         let write = SplitWritePty(Arc::clone(&arc));
124         (read, write)
125     }
126 
127     /// Unsplit `SplitReadPty` and `SplitWritePty` into a `Pty`
128     ///
129     /// # Panics
130     /// If there are more than one copy of SplitReadPty or SplitWritePty, this
131     /// method will panic
132     ///
133     /// # Example
134     ///
135     /// ```no_run
136     /// use ylong_runtime::process::pty_process::Pty;
137     /// let pty = Pty::new().unwrap();
138     /// let pts = pty.pts().unwrap();
139     /// let (read_pty, write_pty) = pty.into_split();
140     /// let mut pty = Pty::unsplit(read_pty, write_pty).expect("unsplit fail!");
141     /// ```
unsplit(read_pty: SplitReadPty, write_pty: SplitWritePty) -> io::Result<Self>142     pub fn unsplit(read_pty: SplitReadPty, write_pty: SplitWritePty) -> io::Result<Self> {
143         let SplitReadPty(read_pty) = read_pty;
144         let SplitWritePty(write_pty) = write_pty;
145         if Arc::ptr_eq(&read_pty, &write_pty) {
146             // drop SplitWritePty to ensure Arc::try_unwrap() successful.
147             drop(write_pty);
148             Ok(Arc::try_unwrap(read_pty)
149                 .expect("there are more than one copy of SplitRead or SplitWrite"))
150         } else {
151             Err(io::Error::new(
152                 io::ErrorKind::InvalidInput,
153                 "the SplitReadPty and the SplitWritePty come from different Pty",
154             ))
155         }
156     }
157 }
158 
159 impl From<Pty> for OwnedFd {
from(value: Pty) -> Self160     fn from(value: Pty) -> Self {
161         // io must be some until deregister
162         value.0.io_take().expect("io deregister failed").into()
163     }
164 }
165 
166 impl AsFd for Pty {
as_fd(&self) -> BorrowedFd<'_>167     fn as_fd(&self) -> BorrowedFd<'_> {
168         (*self.0).as_fd()
169     }
170 }
171 
172 impl AsRawFd for Pty {
as_raw_fd(&self) -> RawFd173     fn as_raw_fd(&self) -> RawFd {
174         AsRawFd::as_raw_fd(&(*self.0))
175     }
176 }
177 
178 impl AsyncRead for Pty {
poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>179     fn poll_read(
180         self: Pin<&mut Self>,
181         cx: &mut Context<'_>,
182         buf: &mut ReadBuf<'_>,
183     ) -> Poll<io::Result<()>> {
184         self.0.poll_read(cx, buf)
185     }
186 }
187 
188 impl AsyncWrite for Pty {
poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>189     fn poll_write(
190         self: Pin<&mut Self>,
191         cx: &mut Context<'_>,
192         buf: &[u8],
193     ) -> Poll<io::Result<usize>> {
194         self.0.poll_write(cx, buf)
195     }
196 
poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>197     fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
198         Poll::Ready(Ok(()))
199     }
200 
poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>201     fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
202         Poll::Ready(Ok(()))
203     }
204 }
205 
206 /// The child end of `Pty`
207 #[derive(Debug)]
208 pub struct Pts(super::sys::PtsInner);
209 
210 impl Pts {
new(pts_inner: super::sys::PtsInner) -> Self211     fn new(pts_inner: super::sys::PtsInner) -> Self {
212         Pts(pts_inner)
213     }
214 
clone_stdio(&self) -> io::Result<Stdio>215     pub(crate) fn clone_stdio(&self) -> io::Result<Stdio> {
216         self.0.clone_stdio()
217     }
218 
session_leader(&self) -> impl FnMut() -> io::Result<()>219     pub(crate) fn session_leader(&self) -> impl FnMut() -> io::Result<()> {
220         self.0.session_leader()
221     }
222 }
223 
224 /// Borrowed read half of a `Pty`
225 #[derive(Debug)]
226 pub struct BorrowReadPty<'a>(&'a Pty);
227 
228 impl AsyncRead for BorrowReadPty<'_> {
poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>229     fn poll_read(
230         self: Pin<&mut Self>,
231         cx: &mut Context<'_>,
232         buf: &mut ReadBuf<'_>,
233     ) -> Poll<io::Result<()>> {
234         self.0 .0.poll_read(cx, buf)
235     }
236 }
237 
238 /// Borrowed write half of a `Pty`
239 #[derive(Debug)]
240 pub struct BorrowWritePty<'a>(&'a Pty);
241 
242 impl BorrowWritePty<'_> {
243     /// Changes the size of the terminal with `Pty`
244     ///
245     /// # Example
246     ///
247     /// ```no_run
248     /// use ylong_runtime::process::pty_process::Pty;
249     ///
250     /// let mut pty = Pty::new().expect("create Pty fail!");
251     /// let (read_pty, write_pty) = pty.split();
252     /// write_pty.resize(24, 80, 0, 0).expect("resize set fail!");
253     /// ```
resize( &self, ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, ) -> io::Result<()>254     pub fn resize(
255         &self,
256         ws_row: u16,
257         ws_col: u16,
258         ws_xpixel: u16,
259         ws_ypixel: u16,
260     ) -> io::Result<()> {
261         self.0.resize(ws_row, ws_col, ws_xpixel, ws_ypixel)
262     }
263 }
264 
265 impl AsyncWrite for BorrowWritePty<'_> {
poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>266     fn poll_write(
267         self: Pin<&mut Self>,
268         cx: &mut Context<'_>,
269         buf: &[u8],
270     ) -> Poll<io::Result<usize>> {
271         self.0 .0.poll_write(cx, buf)
272     }
273 
poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>274     fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
275         Poll::Ready(Ok(()))
276     }
277 
poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>278     fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
279         Poll::Ready(Ok(()))
280     }
281 }
282 
283 /// Read half of a `Pty`
284 #[derive(Debug)]
285 pub struct SplitReadPty(Arc<Pty>);
286 
287 impl AsyncRead for SplitReadPty {
poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>288     fn poll_read(
289         self: Pin<&mut Self>,
290         cx: &mut Context<'_>,
291         buf: &mut ReadBuf<'_>,
292     ) -> Poll<io::Result<()>> {
293         self.0 .0.poll_read(cx, buf)
294     }
295 }
296 
297 /// Write half of a `Pty`
298 #[derive(Debug)]
299 pub struct SplitWritePty(Arc<Pty>);
300 
301 impl SplitWritePty {
302     /// Changes the size of the terminal with `Pty`
303     ///
304     /// # Example
305     ///
306     /// ```no_run
307     /// use ylong_runtime::process::pty_process::Pty;
308     ///
309     /// let mut pty = Pty::new().expect("create Pty fail!");
310     /// let (read_pty, write_pty) = pty.into_split();
311     /// write_pty.resize(24, 80, 0, 0).expect("resize set fail!");
312     /// ```
resize( &self, ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, ) -> io::Result<()>313     pub fn resize(
314         &self,
315         ws_row: u16,
316         ws_col: u16,
317         ws_xpixel: u16,
318         ws_ypixel: u16,
319     ) -> io::Result<()> {
320         self.0.resize(ws_row, ws_col, ws_xpixel, ws_ypixel)
321     }
322 }
323 
324 impl AsyncWrite for SplitWritePty {
poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>325     fn poll_write(
326         self: Pin<&mut Self>,
327         cx: &mut Context<'_>,
328         buf: &[u8],
329     ) -> Poll<io::Result<usize>> {
330         self.0 .0.poll_write(cx, buf)
331     }
332 
poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>333     fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
334         Poll::Ready(Ok(()))
335     }
336 
poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>>337     fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
338         Poll::Ready(Ok(()))
339     }
340 }
341