ptyd: expose PTS number via dup(master, ptsname) for getty slave open
This commit is contained in:
@@ -7,6 +7,7 @@ use syscall::data::TimeSpec;
|
||||
|
||||
mod controlterm;
|
||||
mod pgrp;
|
||||
mod ptsname;
|
||||
mod pty;
|
||||
mod resource;
|
||||
mod scheme;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ use syscall::schemev2::NewFdFlags;
|
||||
|
||||
use crate::controlterm::PtyControlTerm;
|
||||
use crate::pgrp::PtyPgrp;
|
||||
use crate::ptsname::PtyPtsname;
|
||||
use crate::pty::Pty;
|
||||
use crate::resource::Resource;
|
||||
use crate::subterm::PtySubTerm;
|
||||
@@ -126,6 +127,8 @@ impl SchemeSync for PtyScheme {
|
||||
Box::new(PtyTermios::new(old_resource.pty(), old_resource.flags()))
|
||||
} else if buf == b"winsize" {
|
||||
Box::new(PtyWinsize::new(old_resource.pty(), old_resource.flags()))
|
||||
} else if buf == b"ptsname" {
|
||||
Box::new(PtyPtsname::new(old_resource.pty(), old_resource.flags()))
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user