ptyd: implement TIOCGPTN and TIOC{S,G}PTLCK
This functionality is needed according to POSIX. Additionally, some logic had to be changed in order for the ptsname to be correct for the manager terminal (ptmx). If you want to obtain a pty, you must go through the `posix_openpt`-`grantpt`-`unlockpt`-`ptsname`-`open` process. Alternatively, relibc as a function called `openpty`. This is part of my ptyd series. This can be safely merged once the MRs for relibc/ and userutils/ are merged at the same time.
This commit is contained in:
@@ -82,7 +82,7 @@ fn handle(
|
||||
|
||||
fn getpty(columns: u32, lines: u32) -> io::Result<(RawFd, String)> {
|
||||
let master = libredox::call::open(
|
||||
"/scheme/pty",
|
||||
"/scheme/pty/ptmx",
|
||||
libredox::flag::O_CLOEXEC
|
||||
| libredox::flag::O_RDWR
|
||||
| libredox::flag::O_CREAT
|
||||
|
||||
@@ -6,6 +6,7 @@ use syscall::flag::{EventFlags, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
|
||||
|
||||
use crate::pty::Pty;
|
||||
use crate::resource::Resource;
|
||||
use scheme_utils::FpathWriter;
|
||||
|
||||
/// Read side of a pipe
|
||||
pub struct PtyControlTerm {
|
||||
@@ -36,7 +37,10 @@ impl Resource for PtyControlTerm {
|
||||
}
|
||||
|
||||
fn path(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
self.pty.borrow_mut().path(buf)
|
||||
FpathWriter::with(buf, "pty", |w| {
|
||||
write!(w, "{}", "ptmx").unwrap();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
|
||||
@@ -7,6 +7,8 @@ use syscall::data::TimeSpec;
|
||||
|
||||
mod controlterm;
|
||||
mod pgrp;
|
||||
mod ptlock;
|
||||
mod ptname;
|
||||
mod pty;
|
||||
mod resource;
|
||||
mod scheme;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
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 side of a pipe
|
||||
pub struct PtyLock {
|
||||
pty: Weak<RefCell<Pty>>,
|
||||
flags: usize,
|
||||
}
|
||||
|
||||
impl PtyLock {
|
||||
pub fn new(pty: Weak<RefCell<Pty>>, flags: usize) -> Self {
|
||||
PtyLock { pty, flags }
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource for PtyLock {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME assuming c_int has same size as u32
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
if let Some(pty_lock) = self.pty.upgrade() {
|
||||
let pty = pty_lock.borrow();
|
||||
|
||||
let lock_buf = buf
|
||||
.get_mut(..4)
|
||||
.and_then(|b| <&mut [u8; 4]>::try_from(b).ok())
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
*lock_buf = (pty.locked as u32).to_ne_bytes();
|
||||
Ok(4)
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
if let Some(pty_lock) = self.pty.upgrade() {
|
||||
let mut pty = pty_lock.borrow_mut();
|
||||
|
||||
let lock_val = u32::from_ne_bytes(
|
||||
buf.get(..4)
|
||||
.and_then(|b| <[u8; 4]>::try_from(b).ok())
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
);
|
||||
pty.locked = lock_val != 0;
|
||||
Ok(4)
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Weak;
|
||||
|
||||
use syscall::error::{Error, Result, EBADF, EINVAL, EIO, EPIPE};
|
||||
use syscall::flag::{EventFlags, F_GETFL, F_SETFL, O_ACCMODE};
|
||||
|
||||
use crate::pty::Pty;
|
||||
use crate::resource::Resource;
|
||||
|
||||
/// Read side of a pipe
|
||||
pub struct PtsName {
|
||||
pty: Weak<RefCell<Pty>>,
|
||||
flags: usize,
|
||||
}
|
||||
|
||||
impl PtsName {
|
||||
pub fn new(pty: Weak<RefCell<Pty>>, flags: usize) -> Self {
|
||||
PtsName { pty, flags }
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource for PtsName {
|
||||
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 pty = pty_lock.borrow();
|
||||
if pty.locked {
|
||||
Err(Error::new(EIO))
|
||||
} else {
|
||||
let id_buf = buf
|
||||
.get_mut(..4)
|
||||
.and_then(|b| <&mut [u8; 4]>::try_from(b).ok())
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
*id_buf = (pty.id as u32).to_ne_bytes();
|
||||
Ok(4)
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EPIPE))
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, _buf: &[u8]) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use syscall::error::Result;
|
||||
pub struct Pty {
|
||||
pub id: usize,
|
||||
pub pgrp: usize,
|
||||
pub locked: bool,
|
||||
pub termios: Termios,
|
||||
pub winsize: Winsize,
|
||||
pub cooked: Vec<u8>,
|
||||
@@ -21,6 +22,7 @@ impl Pty {
|
||||
Pty {
|
||||
id,
|
||||
pgrp: 0,
|
||||
locked: true,
|
||||
termios: Termios::default(),
|
||||
winsize: Winsize::default(),
|
||||
cooked: Vec::new(),
|
||||
|
||||
@@ -12,6 +12,8 @@ use syscall::schemev2::NewFdFlags;
|
||||
|
||||
use crate::controlterm::PtyControlTerm;
|
||||
use crate::pgrp::PtyPgrp;
|
||||
use crate::ptlock::PtyLock;
|
||||
use crate::ptname::PtsName;
|
||||
use crate::pty::Pty;
|
||||
use crate::resource::Resource;
|
||||
use crate::subterm::PtySubTerm;
|
||||
@@ -72,7 +74,12 @@ impl SchemeSync for PtyScheme {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
// This happens if we are passed "/scheme/pty" and not "/scheme/pty/ptmx".
|
||||
if path.is_empty() {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
if path == "ptmx" {
|
||||
let pty = Rc::new(RefCell::new(Pty::new(id)));
|
||||
self.handles.insert(
|
||||
id,
|
||||
@@ -119,6 +126,10 @@ 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"ptlock" {
|
||||
Box::new(PtyLock::new(old_resource.pty(), old_resource.flags()))
|
||||
} else if buf == b"ptsname" {
|
||||
Box::new(PtsName::new(old_resource.pty(), old_resource.flags()))
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user