//! libc syscalls supporting `rustix::pty`. use crate::backend::c; use crate::backend::conv::{borrowed_fd, ret}; use crate::fd::BorrowedFd; use crate::io; #[cfg(all( feature = "alloc", any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia") ))] use { crate::ffi::{CStr, CString}, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::borrow::ToOwned, alloc::vec::Vec, }; #[cfg(not(linux_kernel))] use crate::{backend::conv::ret_owned_fd, fd::OwnedFd, pty::OpenptFlags}; #[cfg(not(linux_kernel))] #[inline] pub(crate) fn openpt(flags: OpenptFlags) -> io::Result { unsafe { ret_owned_fd(c::posix_openpt(flags.bits() as _)) } } #[cfg(all( feature = "alloc", any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia") ))] #[inline] pub(crate) fn ptsname(fd: BorrowedFd<'_>, mut buffer: Vec) -> io::Result { // This code would benefit from having a better way to read into // uninitialized memory, but that requires `unsafe`. buffer.clear(); buffer.reserve(SMALL_PATH_BUFFER_SIZE); buffer.resize(buffer.capacity(), 0_u8); loop { // On platforms with `ptsname_r`, use it. #[cfg(any(linux_like, target_os = "fuchsia"))] let r = unsafe { c::ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) }; // FreeBSD 12 doesn't have `ptsname_r`. #[cfg(target_os = "freebsd")] let r = unsafe { weak! { fn ptsname_r( c::c_int, *mut c::c_char, c::size_t ) -> c::c_int } if let Some(func) = ptsname_r.get() { func(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) } else { libc::ENOSYS } }; // macOS 10.13.4 has `ptsname_r`; use it if we have it, otherwise fall // back to calling the underlying ioctl directly. #[cfg(apple)] let r = unsafe { weak! { fn ptsname_r(c::c_int, *mut c::c_char, c::size_t) -> c::c_int } if let Some(libc_ptsname_r) = ptsname_r.get() { libc_ptsname_r(borrowed_fd(fd), buffer.as_mut_ptr().cast(), buffer.len()) } else { // The size declared in the `TIOCPTYGNAME` macro in // sys/ttycom.h is 128. let mut name: [u8; 128] = [0_u8; 128]; match c::ioctl(borrowed_fd(fd), c::TIOCPTYGNAME as _, &mut name) { 0 => { let len = CStr::from_ptr(name.as_ptr().cast()).to_bytes().len(); std::ptr::copy_nonoverlapping(name.as_ptr(), buffer.as_mut_ptr(), len + 1); 0 } _ => libc_errno::errno().0, } } }; if r == 0 { return Ok(unsafe { CStr::from_ptr(buffer.as_ptr().cast()).to_owned() }); } if r != c::ERANGE { return Err(io::Errno::from_raw_os_error(r)); } // Use `Vec` reallocation strategy to grow capacity exponentially. buffer.reserve(1); buffer.resize(buffer.capacity(), 0_u8); } } #[inline] pub(crate) fn unlockpt(fd: BorrowedFd<'_>) -> io::Result<()> { unsafe { ret(c::unlockpt(borrowed_fd(fd))) } } #[cfg(not(linux_kernel))] #[inline] pub(crate) fn grantpt(fd: BorrowedFd<'_>) -> io::Result<()> { unsafe { ret(c::grantpt(borrowed_fd(fd))) } }