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