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