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::ffi::CStr;
15 use std::fs::OpenOptions;
16 use std::io;
17 use std::io::{Read, Write};
18 use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
19 use std::os::unix::ffi::OsStrExt;
20 use std::process::Stdio;
21 
22 use ylong_io::sys::SourceFd;
23 use ylong_io::{Interest, Selector, Source, Token};
24 
25 #[derive(Debug)]
26 pub(crate) struct PtyInner(OwnedFd);
27 
28 impl PtyInner {
open() -> io::Result<Self>29     pub(crate) fn open() -> io::Result<Self> {
30         // Can not set CLOEXEC directly because it is linux-specific.
31         let raw = syscall!(posix_openpt(libc::O_RDWR | libc::O_NOCTTY))?;
32 
33         syscall!(grantpt(raw))?;
34         syscall!(unlockpt(raw))?;
35 
36         // Set CLOEXEC.
37         let mut flags = syscall!(fcntl(raw, libc::F_GETFD))?;
38         flags |= libc::O_CLOEXEC;
39         syscall!(fcntl(raw, libc::F_SETFD, flags))?;
40 
41         let fd = unsafe { OwnedFd::from_raw_fd(raw) };
42         Ok(Self(fd))
43     }
44 
set_size( &self, ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, ) -> io::Result<()>45     pub(crate) fn set_size(
46         &self,
47         ws_row: u16,
48         ws_col: u16,
49         ws_xpixel: u16,
50         ws_ypixel: u16,
51     ) -> io::Result<()> {
52         let size = libc::winsize {
53             ws_row,
54             ws_col,
55             ws_xpixel,
56             ws_ypixel,
57         };
58         let raw = self.0.as_raw_fd();
59         syscall!(ioctl(raw, libc::TIOCSWINSZ, std::ptr::addr_of!(size))).map(|_| ())
60     }
61 
pts(&self, size: usize) -> io::Result<PtsInner>62     pub(crate) fn pts(&self, size: usize) -> io::Result<PtsInner> {
63         let mut name_buf: Vec<libc::c_char> = vec![0; size];
64 
65         loop {
66             let res = unsafe {
67                 libc::ptsname_r(
68                     self.0.as_raw_fd(),
69                     name_buf.as_mut_ptr().cast(),
70                     name_buf.len(),
71                 )
72             };
73             match res {
74                 0 => {
75                     name_buf.resize(name_buf.capacity(), 0);
76                     break;
77                 }
78                 // If the vec's capacity is too small, double it.
79                 libc::ERANGE => {
80                     name_buf.reserve(1);
81                     name_buf.resize(name_buf.capacity(), 0)
82                 }
83                 _ => return Err(std::io::Error::last_os_error()),
84             }
85         }
86 
87         let name = unsafe { CStr::from_ptr(name_buf.as_ptr()) }.to_owned();
88         let path = std::ffi::OsStr::from_bytes(name.as_bytes());
89 
90         let file = OpenOptions::new().read(true).write(true).open(path)?;
91         Ok(PtsInner(file.into()))
92     }
93 
set_nonblocking(&self) -> io::Result<()>94     pub(crate) fn set_nonblocking(&self) -> io::Result<()> {
95         let mut flags = syscall!(fcntl(self.0.as_raw_fd(), libc::F_GETFL))?;
96         flags |= libc::O_NONBLOCK;
97         syscall!(fcntl(self.0.as_raw_fd(), libc::F_SETFL, flags)).map(|_| ())
98     }
99 }
100 
101 impl AsFd for PtyInner {
as_fd(&self) -> BorrowedFd<'_>102     fn as_fd(&self) -> BorrowedFd<'_> {
103         self.0.as_fd()
104     }
105 }
106 
107 impl AsRawFd for PtyInner {
as_raw_fd(&self) -> RawFd108     fn as_raw_fd(&self) -> RawFd {
109         self.0.as_raw_fd()
110     }
111 }
112 
113 impl From<PtyInner> for OwnedFd {
from(value: PtyInner) -> Self114     fn from(value: PtyInner) -> Self {
115         value.0
116     }
117 }
118 
119 macro_rules! impl_read_write {
120     ($type:ty) => {
121         impl Read for $type {
122             fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
123                 syscall!(read(
124                     self.0.as_raw_fd(),
125                     buf.as_mut_ptr().cast::<libc::c_void>(),
126                     buf.len() as libc::size_t
127                 ))
128                 .map(|res| res as usize)
129             }
130         }
131 
132         impl Write for $type {
133             fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
134                 syscall!(write(
135                     self.0.as_raw_fd(),
136                     buf.as_ptr().cast::<libc::c_void>(),
137                     buf.len() as libc::size_t
138                 ))
139                 .map(|res| res as usize)
140             }
141 
142             fn flush(&mut self) -> io::Result<()> {
143                 Ok(())
144             }
145         }
146     };
147 }
148 
149 impl_read_write!(PtyInner);
150 impl_read_write!(&PtyInner);
151 
152 impl Source for PtyInner {
register( &mut self, selector: &Selector, token: Token, interests: Interest, ) -> io::Result<()>153     fn register(
154         &mut self,
155         selector: &Selector,
156         token: Token,
157         interests: Interest,
158     ) -> io::Result<()> {
159         SourceFd(&self.get_fd()).register(selector, token, interests)
160     }
161 
deregister(&mut self, selector: &Selector) -> io::Result<()>162     fn deregister(&mut self, selector: &Selector) -> io::Result<()> {
163         SourceFd(&self.get_fd()).deregister(selector)
164     }
165 
get_fd(&self) -> ylong_io::Fd166     fn get_fd(&self) -> ylong_io::Fd {
167         self.0.as_raw_fd()
168     }
169 }
170 
171 #[derive(Debug)]
172 pub(crate) struct PtsInner(OwnedFd);
173 
174 impl PtsInner {
clone_stdio(&self) -> io::Result<Stdio>175     pub(crate) fn clone_stdio(&self) -> io::Result<Stdio> {
176         Ok(self.0.try_clone()?.into())
177     }
178 
session_leader(&self) -> impl FnMut() -> io::Result<()>179     pub(crate) fn session_leader(&self) -> impl FnMut() -> io::Result<()> {
180         let fd = self.0.as_raw_fd();
181         move || {
182             syscall!(setsid())?;
183             syscall!(ioctl(fd, libc::TIOCSCTTY, std::ptr::null::<libc::c_int>()))?;
184             Ok(())
185         }
186     }
187 }
188 
189 impl From<PtsInner> for OwnedFd {
from(value: PtsInner) -> Self190     fn from(value: PtsInner) -> Self {
191         value.0
192     }
193 }
194 
195 impl AsFd for PtsInner {
as_fd(&self) -> BorrowedFd<'_>196     fn as_fd(&self) -> BorrowedFd<'_> {
197         self.0.as_fd()
198     }
199 }
200 
201 impl AsRawFd for PtsInner {
as_raw_fd(&self) -> RawFd202     fn as_raw_fd(&self) -> RawFd {
203         self.0.as_raw_fd()
204     }
205 }
206 
207 #[cfg(test)]
208 mod tests {
209     use std::io::{Read, Write};
210     use std::os::fd::{AsFd, AsRawFd, OwnedFd};
211 
212     use crate::process::pty_process::sys::PtyInner;
213 
214     /// Basic UT test cases for `PtyInner.pts()`.
215     ///
216     /// # Brief
217     /// 1. Open a new `PtyInner`.
218     /// 2. Call pts() with small size.
219     /// 3. Check result is correct.
220     #[test]
ut_pty_pts_size_test()221     fn ut_pty_pts_size_test() {
222         let pty = PtyInner::open().unwrap();
223         let pts = pty.pts(1);
224         assert!(pts.is_ok());
225         let pts = pts.unwrap();
226         assert!(pts.as_fd().as_raw_fd() >= 0);
227         assert!(pts.as_raw_fd() >= 0);
228         let fd = OwnedFd::from(pts);
229         assert!(fd.as_raw_fd() >= 0);
230     }
231 
232     /// Basic UT test cases for `PtyInner` read and write.
233     ///
234     /// # Brief
235     /// 1. Open a new `PtyInner`.
236     /// 2. Write something into `PtyInner`.
237     /// 3. Check read result is correct.
238     #[test]
ut_pty_read_write_test()239     fn ut_pty_read_write_test() {
240         let mut pty = PtyInner::open().unwrap();
241         let arg = "hello world!";
242         pty.write_all(arg.as_bytes()).unwrap();
243 
244         let mut buf = [0; 12];
245         pty.read_exact(&mut buf).unwrap();
246         assert_eq!(buf, arg.as_bytes());
247     }
248 }
249