• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! libc syscalls supporting `rustix::pty`.
2 
3 use crate::backend::c;
4 use crate::backend::conv::{borrowed_fd, ret};
5 use crate::fd::BorrowedFd;
6 use crate::io;
7 #[cfg(all(
8     feature = "alloc",
9     any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia")
10 ))]
11 use {
12     crate::ffi::{CStr, CString},
13     crate::path::SMALL_PATH_BUFFER_SIZE,
14     alloc::borrow::ToOwned,
15     alloc::vec::Vec,
16 };
17 
18 #[cfg(not(linux_kernel))]
19 use crate::{backend::conv::ret_owned_fd, fd::OwnedFd, pty::OpenptFlags};
20 
21 use errno as libc_errno;
22 
23 #[cfg(not(linux_kernel))]
24 #[inline]
openpt(flags: OpenptFlags) -> io::Result<OwnedFd>25 pub(crate) fn openpt(flags: OpenptFlags) -> io::Result<OwnedFd> {
26     unsafe { ret_owned_fd(c::posix_openpt(flags.bits() as _)) }
27 }
28 
29 #[cfg(all(
30     feature = "alloc",
31     any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia")
32 ))]
33 #[inline]
ptsname(fd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString>34 pub(crate) fn ptsname(fd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString> {
35     // This code would benefit from having a better way to read into
36     // uninitialized memory, but that requires `unsafe`.
37     buffer.clear();
38     buffer.reserve(SMALL_PATH_BUFFER_SIZE);
39     buffer.resize(buffer.capacity(), 0_u8);
40 
41     loop {
42         // On platforms with `ptsname_r`, use it.
43         #[cfg(any(linux_like, target_os = "fuchsia"))]
44         let r = unsafe { c::ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) };
45 
46         // FreeBSD 12 doesn't have `ptsname_r`.
47         #[cfg(target_os = "freebsd")]
48         let r = unsafe {
49             weak! {
50                 fn ptsname_r(
51                      c::c_int,
52                      *mut c::c_char,
53                      c::size_t
54                 ) -> c::c_int
55             }
56             if let Some(func) = ptsname_r.get() {
57                 func(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len())
58             } else {
59                 libc::ENOSYS
60             }
61         };
62 
63         // macOS 10.13.4 has `ptsname_r`; use it if we have it, otherwise fall
64         // back to calling the underlying ioctl directly.
65         #[cfg(apple)]
66         let r = unsafe {
67             weak! { fn ptsname_r(c::c_int, *mut c::c_char, c::size_t) -> c::c_int }
68 
69             if let Some(libc_ptsname_r) = ptsname_r.get() {
70                 libc_ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len())
71             } else {
72                 // The size declared in the `TIOCPTYGNAME` macro in
73                 // sys/ttycom.h is 128.
74                 let mut name: [u8; 128] = [0_u8; 128];
75                 match c::ioctl(borrowed_fd(fd), c::TIOCPTYGNAME as _, &mut name) {
76                     0 => {
77                         let len = CStr::from_ptr(name.as_ptr().cast()).to_bytes().len();
78                         std::ptr::copy_nonoverlapping(name.as_ptr(), buffer.as_mut_ptr(), len + 1);
79                         0
80                     }
81                     _ => libc_errno::errno().0,
82                 }
83             }
84         };
85 
86         if r == 0 {
87             return Ok(unsafe { CStr::from_ptr(buffer.as_ptr().cast()).to_owned() });
88         }
89         if r != c::ERANGE {
90             return Err(io::Errno::from_raw_os_error(r));
91         }
92 
93         // Use `Vec` reallocation strategy to grow capacity exponentially.
94         buffer.reserve(1);
95         buffer.resize(buffer.capacity(), 0_u8);
96     }
97 }
98 
99 #[inline]
unlockpt(fd: BorrowedFd<'_>) -> io::Result<()>100 pub(crate) fn unlockpt(fd: BorrowedFd<'_>) -> io::Result<()> {
101     unsafe { ret(c::unlockpt(borrowed_fd(fd))) }
102 }
103 
104 #[cfg(not(linux_kernel))]
105 #[inline]
grantpt(fd: BorrowedFd<'_>) -> io::Result<()>106 pub(crate) fn grantpt(fd: BorrowedFd<'_>) -> io::Result<()> {
107     unsafe { ret(c::grantpt(borrowed_fd(fd))) }
108 }
109