#[cfg(target_os = "macos")]
mod ptsname_r_macos;
use crate::descriptor::{self, DescriptorError};
use std::{
error::Error,
ffi::CStr,
fmt, io,
os::{
fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd},
unix::io::RawFd,
},
sync::Arc,
};
pub type Result<T> = ::std::result::Result<T, MasterError>;
#[derive(Clone, Copy, Debug)]
pub enum MasterError {
BadDescriptor(DescriptorError),
GrantptError,
UnlockptError,
PtsnameError,
}
impl fmt::Display for MasterError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", ::errno::errno())
}
}
impl Error for MasterError {
fn description(&self) -> &str {
match *self {
MasterError::BadDescriptor(_) => "the descriptor as occured an error",
MasterError::GrantptError => "the `grantpt` has a error, errnois set appropriately.",
MasterError::UnlockptError => "the `grantpt` has a error, errnois set appropriately.",
MasterError::PtsnameError => "the `ptsname` has a error",
}
}
fn cause(&self) -> Option<&dyn Error> {
match *self {
MasterError::BadDescriptor(ref err) => Some(err),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct Master {
pty: Arc<OwnedFd>,
}
impl Master {
pub fn new(path: &CStr) -> Result<Self> {
match descriptor::open(path, libc::O_RDWR, None) {
Err(cause) => Err(MasterError::BadDescriptor(cause)),
Ok(fd) => Ok(Master { pty: Arc::new(fd) }),
}
}
pub fn raw_fd(&self) -> RawFd {
self.pty.as_raw_fd()
}
pub fn borrow_fd(&self) -> BorrowedFd<'_> {
self.pty.as_fd()
}
pub fn grantpt(&self) -> Result<libc::c_int> {
unsafe {
match libc::grantpt(self.raw_fd()) {
-1 => Err(MasterError::GrantptError),
c => Ok(c),
}
}
}
pub fn unlockpt(&self) -> Result<libc::c_int> {
unsafe {
match libc::unlockpt(self.raw_fd()) {
-1 => Err(MasterError::UnlockptError),
c => Ok(c),
}
}
}
pub fn ptsname_r(&self, buf: &mut [u8]) -> Result<()> {
unsafe {
let data: *mut u8 = &mut buf[0];
#[cfg(any(target_os = "linux", target_os = "android"))]
let result = libc::ptsname_r(self.raw_fd(), data as *mut libc::c_char, buf.len());
#[cfg(target_os = "macos")]
let result =
ptsname_r_macos::ptsname_r(self.raw_fd(), data as *mut libc::c_char, buf.len());
match result {
0 => Ok(()),
_ => Err(MasterError::PtsnameError), }
}
}
}
impl io::Read for Master {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
match libc::read(self.raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, buf.len()) {
-1 => Ok(0),
len => Ok(len as usize),
}
}
}
}
impl io::Write for Master {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
match libc::write(self.raw_fd(), buf.as_ptr() as *const libc::c_void, buf.len()) {
-1 => Err(io::Error::last_os_error()),
ret => Ok(ret as usize),
}
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}