Files
RedBear-OS/ptyd/src/ptsname.rs
T

87 lines
2.4 KiB
Rust

use std::cell::RefCell;
use std::rc::Weak;
use syscall::error::{Error, Result, EBADF, EINVAL, EPIPE};
use syscall::flag::{EventFlags, F_GETFL, F_SETFL, O_ACCMODE};
use crate::pty::Pty;
use crate::resource::Resource;
/// Read-only resource exposing the PTY's numeric id.
///
/// relibc's `ptsname`/`ptsname_r` resolve the subterminal path via the
/// `TIOCGPTN` ioctl, which does `dup(master, "ptsname")` and reads a
/// `c_int` (4 bytes) — the PTS number — then formats `/scheme/pty/<n>`.
/// Without this handler ptyd's `dup` returned `EINVAL` for "ptsname", so
/// `ptsname` failed, getty resolved a bogus slave path, and it panicked
/// with "failed to open slave stdin: No such file or directory". Because
/// `Pty::id` is also the master's scheme handle id, returning it here makes
/// the subsequent `/scheme/pty/<n>` slave open resolve to the right master.
pub struct PtyPtsname {
pty: Weak<RefCell<Pty>>,
flags: usize,
}
impl PtyPtsname {
pub fn new(pty: Weak<RefCell<Pty>>, flags: usize) -> Self {
PtyPtsname { pty, flags }
}
}
impl Resource for PtyPtsname {
fn pty(&self) -> Weak<RefCell<Pty>> {
self.pty.clone()
}
fn flags(&self) -> usize {
self.flags
}
fn path(&mut self, buf: &mut [u8]) -> Result<usize> {
if let Some(pty_lock) = self.pty.upgrade() {
pty_lock.borrow_mut().path(buf)
} else {
Err(Error::new(EPIPE))
}
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if let Some(pty_lock) = self.pty.upgrade() {
let id = pty_lock.borrow().id as i32;
let bytes = id.to_ne_bytes();
let n = core::cmp::min(buf.len(), bytes.len());
buf[..n].copy_from_slice(&bytes[..n]);
Ok(n)
} else {
Ok(0)
}
}
fn write(&mut self, _buf: &[u8]) -> Result<usize> {
Err(Error::new(EINVAL))
}
fn sync(&mut self) -> Result<()> {
Ok(())
}
fn fcntl(&mut self, cmd: usize, arg: usize) -> Result<usize> {
match cmd {
F_GETFL => Ok(self.flags),
F_SETFL => {
self.flags = (self.flags & O_ACCMODE) | (arg & !O_ACCMODE);
Ok(0)
}
_ => Err(Error::new(EINVAL)),
}
}
fn fevent(&mut self) -> Result<EventFlags> {
Err(Error::new(EBADF))
}
fn events(&mut self) -> EventFlags {
EventFlags::empty()
}
}