Merge branch 'ptyd-improvements' into 'main'
ptyd: implement TIOCGPTN and TIOC{S,G}PTLCK
See merge request redox-os/base!276
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