diff --git a/drivers/redoxerd/src/main.rs b/drivers/redoxerd/src/main.rs index 5ecd0b4672..4551ea2e5d 100644 --- a/drivers/redoxerd/src/main.rs +++ b/drivers/redoxerd/src/main.rs @@ -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 diff --git a/ptyd/src/controlterm.rs b/ptyd/src/controlterm.rs index f1f6fc42f8..ae8011c905 100644 --- a/ptyd/src/controlterm.rs +++ b/ptyd/src/controlterm.rs @@ -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 { - self.pty.borrow_mut().path(buf) + FpathWriter::with(buf, "pty", |w| { + write!(w, "{}", "ptmx").unwrap(); + Ok(()) + }) } fn read(&mut self, buf: &mut [u8]) -> Result { diff --git a/ptyd/src/main.rs b/ptyd/src/main.rs index e6bf429eb8..6eec7ea161 100644 --- a/ptyd/src/main.rs +++ b/ptyd/src/main.rs @@ -7,6 +7,8 @@ use syscall::data::TimeSpec; mod controlterm; mod pgrp; +mod ptlock; +mod ptname; mod pty; mod resource; mod scheme; diff --git a/ptyd/src/ptlock.rs b/ptyd/src/ptlock.rs new file mode 100644 index 0000000000..c6d742b3cb --- /dev/null +++ b/ptyd/src/ptlock.rs @@ -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>, + flags: usize, +} + +impl PtyLock { + pub fn new(pty: Weak>, flags: usize) -> Self { + PtyLock { pty, flags } + } +} + +impl Resource for PtyLock { + fn pty(&self) -> Weak> { + self.pty.clone() + } + + fn flags(&self) -> usize { + self.flags + } + + fn path(&mut self, buf: &mut [u8]) -> Result { + 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 { + 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 { + 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 { + 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 { + Err(Error::new(EBADF)) + } + + fn events(&mut self) -> EventFlags { + EventFlags::empty() + } +} diff --git a/ptyd/src/ptname.rs b/ptyd/src/ptname.rs new file mode 100644 index 0000000000..434d5dd5a0 --- /dev/null +++ b/ptyd/src/ptname.rs @@ -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>, + flags: usize, +} + +impl PtsName { + pub fn new(pty: Weak>, flags: usize) -> Self { + PtsName { pty, flags } + } +} + +impl Resource for PtsName { + fn pty(&self) -> Weak> { + self.pty.clone() + } + + fn flags(&self) -> usize { + self.flags + } + + fn path(&mut self, buf: &mut [u8]) -> Result { + 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 { + 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 { + Err(Error::new(EBADF)) + } + + fn sync(&mut self) -> Result<()> { + Ok(()) + } + + fn fcntl(&mut self, cmd: usize, arg: usize) -> Result { + 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 { + Err(Error::new(EBADF)) + } + + fn events(&mut self) -> EventFlags { + EventFlags::empty() + } +} diff --git a/ptyd/src/pty.rs b/ptyd/src/pty.rs index bcc46ac35a..933bb80768 100644 --- a/ptyd/src/pty.rs +++ b/ptyd/src/pty.rs @@ -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, @@ -21,6 +22,7 @@ impl Pty { Pty { id, pgrp: 0, + locked: true, termios: Termios::default(), winsize: Winsize::default(), cooked: Vec::new(), diff --git a/ptyd/src/scheme.rs b/ptyd/src/scheme.rs index c7136a4e81..2d34ac3cb4 100644 --- a/ptyd/src/scheme.rs +++ b/ptyd/src/scheme.rs @@ -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)); }