use std::cell::RefCell; use std::rc::Weak; use syscall::error::{Error, Result, EINVAL, EPIPE, EAGAIN}; use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK}; use pty::Pty; use resource::Resource; /// Read side of a pipe #[derive(Clone)] pub struct PtySlave { pty: Weak>, flags: usize, notified_read: bool, notified_write: bool } impl PtySlave { pub fn new(pty: Weak>, flags: usize) -> Self { PtySlave { pty: pty, flags: flags, notified_read: false, notified_write: false } } } impl Resource for PtySlave { 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 mut pty = pty_lock.borrow_mut(); if let Some(packet) = pty.mosi.pop_front() { let mut i = 0; while i < buf.len() && i < packet.len() { buf[i] = packet[i]; i += 1; } if i < packet.len() { pty.mosi.push_front(packet[i..].to_vec()); } Ok(Some(i)) } else if self.flags & O_NONBLOCK == O_NONBLOCK { Err(Error::new(EAGAIN)) } else { Ok(None) } } else { Ok(Some(0)) } } fn write(&self, buf: &[u8]) -> Result> { if let Some(pty_lock) = self.pty.upgrade() { let mut pty = pty_lock.borrow_mut(); if pty.miso.len() >= 64 { return Ok(None); } pty.output(buf); Ok(Some(buf.len())) } else { Err(Error::new(EPIPE)) } } fn sync(&self) -> Result { if let Some(pty_lock) = self.pty.upgrade() { let mut pty = pty_lock.borrow_mut(); pty.miso.push_back(vec![1]); Ok(0) } else { Err(Error::new(EPIPE)) } } 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<()> { self.notified_read = false; // resend self.notified_write = false; Ok(()) } fn fevent_count(&mut self) -> Option { if let Some(pty_lock) = self.pty.upgrade() { let pty = pty_lock.borrow(); if let Some(data) = pty.mosi.front() { if !self.notified_read { self.notified_read = true; Some(data.len()) } else { None } } else { self.notified_read = false; None } } else { Some(0) } } fn fevent_writable(&mut self) -> bool { let notified = self.notified_write; self.notified_write = true; !notified } }