#![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",
target_os = "illumos"
)
))]
use {crate::ffi::CString, alloc::vec::Vec};
#[cfg(target_os = "linux")]
use crate::{fd::FromRawFd as _, ioctl};
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct OpenptFlags: u32 {
const RDWR = c::O_RDWR as c::c_uint;
#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "l4re", target_os = "redox", target_os = "vita")))]
const NOCTTY = c::O_NOCTTY as c::c_uint;
#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "netbsd"))]
const CLOEXEC = c::O_CLOEXEC as c::c_uint;
const _ = !0;
}
}
impl From<OpenptFlags> for OFlags {
#[inline]
fn from(flags: OpenptFlags) -> Self {
Self::from_bits_retain(flags.bits() as _)
}
}
#[inline]
#[doc(alias = "posix_openpt")]
pub fn openpt(flags: OpenptFlags) -> io::Result<OwnedFd> {
#[cfg(linux_kernel)]
{
use crate::fs::{open, Mode};
match open(cstr!("/dev/ptmx"), flags.into(), Mode::empty()) {
Err(io::Errno::NOSPC) => Err(io::Errno::AGAIN),
otherwise => otherwise,
}
}
#[cfg(not(linux_kernel))]
{
backend::pty::syscalls::openpt(flags)
}
}
#[cfg(all(
feature = "alloc",
any(
apple,
linux_like,
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos"
)
))]
#[inline]
#[doc(alias = "ptsname_r")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
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())
}
#[inline]
pub fn unlockpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
backend::pty::syscalls::unlockpt(fd.as_fd())
}
#[inline]
pub fn grantpt<Fd: AsFd>(fd: Fd) -> io::Result<()> {
#[cfg(not(linux_kernel))]
{
backend::pty::syscalls::grantpt(fd.as_fd())
}
#[cfg(linux_kernel)]
{
let _ = fd;
Ok(())
}
}
#[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;
fn opcode(&self) -> ioctl::Opcode {
c::TIOCGPTPEER as ioctl::Opcode
}
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))
}
}