|
| 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