From 36a34e70b2d47cd1564366a4e7725aec6c207ddc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Jul 2017 10:53:24 -0600 Subject: [PATCH] Add termios read/write file --- src/main.rs | 1 + src/master.rs | 4 ++ src/resource.rs | 2 + src/scheme.rs | 14 ++++--- src/slave.rs | 4 ++ src/termios.rs | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/termios.rs diff --git a/src/main.rs b/src/main.rs index c3940bf2a5..d31023ccd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ mod pty; mod resource; mod scheme; mod slave; +mod termios; use scheme::PtyScheme; diff --git a/src/master.rs b/src/master.rs index 74f18d8273..7660d17e45 100644 --- a/src/master.rs +++ b/src/master.rs @@ -31,6 +31,10 @@ impl Resource for PtyMaster { fn pty(&self) -> Weak> { Rc::downgrade(&self.pty) } + + fn flags(&self) -> usize { + self.flags + } fn path(&self, buf: &mut [u8]) -> Result { self.pty.borrow_mut().path(buf) diff --git a/src/resource.rs b/src/resource.rs index 27f5bff606..a6dcb4714e 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -8,6 +8,8 @@ use pty::Pty; pub trait Resource { fn boxed_clone(&self) -> Box; fn pty(&self) -> Weak>; + fn flags(&self) -> usize; + fn path(&self, buf: &mut [u8]) -> Result; fn read(&self, buf: &mut [u8]) -> Result; fn write(&self, buf: &[u8]) -> Result; diff --git a/src/scheme.rs b/src/scheme.rs index 93783ef776..8d5dee1fbb 100644 --- a/src/scheme.rs +++ b/src/scheme.rs @@ -12,6 +12,7 @@ use master::PtyMaster; use pty::Pty; use resource::Resource; use slave::PtySlave; +use termios::PtyTermios; pub struct PtyScheme { next_id: usize, @@ -56,13 +57,16 @@ impl SchemeMut for PtyScheme { } fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result { - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - let handle = { let old_handle = self.handles.get(&old_id).ok_or(Error::new(EBADF))?; - old_handle.boxed_clone() + + if buf.is_empty() { + old_handle.boxed_clone() + } else if buf == b"termios" { + Box::new(PtyTermios::new(old_handle.pty(), old_handle.flags())) + } else { + return Err(Error::new(EINVAL)); + } }; let id = self.next_id; diff --git a/src/slave.rs b/src/slave.rs index 17e2b8a19b..604bf745e8 100644 --- a/src/slave.rs +++ b/src/slave.rs @@ -32,6 +32,10 @@ impl Resource for PtySlave { self.pty.clone() } + fn flags(&self) -> usize { + self.flags + } + fn path(&self, buf: &mut [u8]) -> Result { if let Some(pty_lock) = self.pty.upgrade() { pty_lock.borrow_mut().path(buf) diff --git a/src/termios.rs b/src/termios.rs new file mode 100644 index 0000000000..a9bac08040 --- /dev/null +++ b/src/termios.rs @@ -0,0 +1,102 @@ +use std::cell::RefCell; +use std::ops::{Deref, DerefMut}; +use std::rc::Weak; + +use syscall::error::{Error, Result, EBADF, EINVAL, EPIPE}; +use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE}; + +use pty::Pty; +use resource::Resource; + +/// Read side of a pipe +#[derive(Clone)] +pub struct PtyTermios { + pty: Weak>, + flags: usize, +} + +impl PtyTermios { + pub fn new(pty: Weak>, flags: usize) -> Self { + PtyTermios { + pty: pty, + flags: flags, + } + } +} + +impl Resource for PtyTermios { + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn pty(&self) -> Weak> { + self.pty.clone() + } + + fn flags(&self) -> usize { + self.flags + } + + fn path(&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(&self, buf: &mut [u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let pty = pty_lock.borrow(); + let termios: &[u8] = pty.termios.deref(); + + let mut i = 0; + while i < buf.len() && i < termios.len() { + buf[i] = termios[i]; + i += 1; + } + Ok(i) + } else { + Ok(0) + } + } + + fn write(&self, buf: &[u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let mut pty = pty_lock.borrow_mut(); + let termios: &mut [u8] = pty.termios.deref_mut(); + + let mut i = 0; + while i < buf.len() && i < termios.len() { + termios[i] = buf[i]; + i += 1; + } + Ok(i) + } else { + Err(Error::new(EPIPE)) + } + } + + fn sync(&self) -> Result { + Ok(0) + } + + 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(&self) -> Result<()> { + Err(Error::new(EBADF)) + } + + fn fevent_count(&self) -> Option { + None + } +}