diff options
Diffstat (limited to 'vendor/rustix/src/pty.rs')
-rw-r--r-- | vendor/rustix/src/pty.rs | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/vendor/rustix/src/pty.rs b/vendor/rustix/src/pty.rs new file mode 100644 index 0000000..926ebf7 --- /dev/null +++ b/vendor/rustix/src/pty.rs @@ -0,0 +1,207 @@ +//! Pseudoterminal operations. +//! +//! For the `openpty` and `login_tty` functions, see the +//! [rustix-openpty crate]. +//! +//! [rustix-openpty crate]: https://crates.io/crates/rustix-openpty + +#![allow(unsafe_code)] + +use crate::backend::c; +use crate::fd::{AsFd, OwnedFd}; +use crate::fs::OFlags; +use crate::{backend, io}; +#[cfg(all( + feature = "alloc", + any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia") +))] +use {crate::ffi::CString, alloc::vec::Vec}; + +#[cfg(target_os = "linux")] +use crate::{fd::FromRawFd, ioctl}; + +bitflags::bitflags! { + /// `O_*` flags for use with [`openpt`] and [`ioctl_tiocgptpeer`]. + /// + /// [`ioctl_tiocgptpeer`]: https://docs.rs/rustix/*/x86_64-unknown-linux-gnu/rustix/pty/fn.ioctl_tiocgptpeer.html + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct OpenptFlags: u32 { + /// `O_RDWR` + const RDWR = c::O_RDWR as c::c_uint; + + /// `O_NOCTTY` + #[cfg(not(any(target_os = "espidf", target_os = "l4re", target_os = "redox", target_os = "vita")))] + const NOCTTY = c::O_NOCTTY as c::c_uint; + + /// `O_CLOEXEC` + /// + /// The standard `posix_openpt` function doesn't support `CLOEXEC`, but + /// rustix supports it on Linux, and FreeBSD and NetBSD support it. + #[cfg(any(linux_kernel, target_os = "freebsd", target_os = "netbsd"))] + const CLOEXEC = c::O_CLOEXEC as c::c_uint; + + /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> + const _ = !0; + } +} + +impl From<OpenptFlags> for OFlags { + #[inline] + fn from(flags: OpenptFlags) -> Self { + // `OpenptFlags` is a subset of `OFlags`. + Self::from_bits_retain(flags.bits() as _) + } +} + +/// `posix_openpt(flags)`—Open a pseudoterminal device. +/// +/// On Linux, an additional `CLOEXEC` flag value may be passed to request the +/// close-on-exec flag be set. +/// +/// On Linux, if the system has no free pseudoterminals available, the +/// underlying system call fails with [`io::Errno::NOSPC`], however this rustix +/// function translates that to [`io::Errno::AGAIN`], so that the linux_raw and +/// libc backends have the same behavior. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [DragonFly BSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html +/// [Linux]: https://man7.org/linux/man-pages/man3/posix_openpt.3.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/posix_openpt.3.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=posix_openpt&sektion=2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=posix_openpt§ion=3 +/// [NetBSD]: https://man.netbsd.org/posix_openpt.3 +/// [OpenBSD]: https://man.openbsd.org/posix_openpt +/// [illumos]: https://illumos.org/man/3C/posix_openpt +#[inline] +#[doc(alias = "posix_openpt")] +pub fn openpt(flags: OpenptFlags) -> io::Result<OwnedFd> { + // On Linux, open the device ourselves so that we can support `CLOEXEC`. + #[cfg(linux_kernel)] + { + use crate::fs::{open, Mode}; + match open(cstr!("/dev/ptmx"), flags.into(), Mode::empty()) { + // Match libc `openat` behavior with `ENOSPC`. + Err(io::Errno::NOSPC) => Err(io::Errno::AGAIN), + otherwise => otherwise, + } + } + + // On all other platforms, use `openpt`. + #[cfg(not(linux_kernel))] + { + backend::pty::syscalls::openpt(flags) + } +} + +/// `ptsname(fd)`—Return the name of a pseudoterminal. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/ptsname.html +/// [Linux]: https://man7.org/linux/man-pages/man3/ptsname.3.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Allocation.html#index-ptsname +#[cfg(all( + feature = "alloc", + any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia") +))] +#[inline] +#[doc(alias = "ptsname_r")] +pub fn ptsname<Fd: AsFd, B: Into<Vec<u8>>>(fd: Fd, reuse: B) -> io::Result<CString> { + backend::pty::syscalls::ptsname(fd.as_fd(), reuse.into()) +} + +/// `unlockpt(fd)`—Unlock a pseudoterminal. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html +/// [Linux]: https://man7.org/linux/man-pages/man3/unlockpt.3.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Allocation.html#index-unlockpt +#[inline] +pub fn unlockpt<Fd: AsFd>(fd: Fd) -> io::Result<()> { + backend::pty::syscalls::unlockpt(fd.as_fd()) +} + +/// `grantpt(fd)`—Grant access to the user side of a pseudoterminal. +/// +/// On Linux, calling this function has no effect, as the kernel is expected to +/// grant the appropriate access. On all other platorms, this function has +/// unspecified behavior if the calling process has a [`Signal::Child`] signal +/// handler installed. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [glibc] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html +/// [Linux]: https://man7.org/linux/man-pages/man3/grantpt.3.html +/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Allocation.html#index-grantpt +/// [`Signal::Child`]: crate::process::Signal::Child +#[inline] +pub fn grantpt<Fd: AsFd>(fd: Fd) -> io::Result<()> { + #[cfg(not(linux_kernel))] + { + backend::pty::syscalls::grantpt(fd.as_fd()) + } + + // On Linux, we assume the kernel has already granted the needed + // permissions to the user side of the pseudoterminal. + #[cfg(linux_kernel)] + { + let _ = fd; + Ok(()) + } +} + +/// `ioctl(fd, TIOCGPTPEER)`—Open the user side of a pseduoterminal. +/// +/// This function is currently only implemented on Linux. +/// +/// # References +/// - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_tty.2.html +#[cfg(target_os = "linux")] +#[inline] +pub fn ioctl_tiocgptpeer<Fd: AsFd>(fd: Fd, flags: OpenptFlags) -> io::Result<OwnedFd> { + unsafe { ioctl::ioctl(fd, Tiocgptpeer(flags)) } +} + +#[cfg(target_os = "linux")] +struct Tiocgptpeer(OpenptFlags); + +#[cfg(target_os = "linux")] +unsafe impl ioctl::Ioctl for Tiocgptpeer { + type Output = OwnedFd; + + const IS_MUTATING: bool = false; + const OPCODE: ioctl::Opcode = ioctl::Opcode::old(c::TIOCGPTPEER as ioctl::RawOpcode); + + fn as_ptr(&mut self) -> *mut c::c_void { + self.0.bits() as *mut c::c_void + } + + unsafe fn output_from_ptr( + ret: ioctl::IoctlOutput, + _arg: *mut c::c_void, + ) -> io::Result<Self::Output> { + Ok(OwnedFd::from_raw_fd(ret)) + } +} |