From 854b6470c49b93ceef0601a995e356d64c19e819 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Jul 2017 10:27:46 -0600 Subject: [PATCH] Use termios crate (WIP) --- Cargo.toml | 1 + src/main.rs | 389 +++--------------------------------------------- src/master.rs | 103 +++++++++++++ src/pty.rs | 66 ++++++++ src/resource.rs | 18 +++ src/scheme.rs | 121 +++++++++++++++ src/slave.rs | 120 +++++++++++++++ 7 files changed, 449 insertions(+), 369 deletions(-) create mode 100644 src/master.rs create mode 100644 src/pty.rs create mode 100644 src/resource.rs create mode 100644 src/scheme.rs create mode 100644 src/slave.rs diff --git a/Cargo.toml b/Cargo.toml index 093da85bca..1446d9f43a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" [dependencies] redox_syscall = "0.1" +redox_termios = { git = "https://github.com/redox-os/termios.git" } diff --git a/src/main.rs b/src/main.rs index f19ab3bf93..c3940bf2a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,327 +1,22 @@ #![deny(warnings)] +extern crate redox_termios; extern crate syscall; -use std::cell::RefCell; -use std::collections::{BTreeMap, VecDeque}; use std::fs::File; use std::io::{Read, Write}; -use std::rc::{Rc, Weak}; -use std::str; -use syscall::data::{Packet, Stat}; -use syscall::error::{Error, Result, EBADF, EINVAL, ENOENT, EPIPE, EWOULDBLOCK}; -use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_CHR}; +use syscall::data::Packet; +use syscall::error::EWOULDBLOCK; use syscall::scheme::SchemeMut; -#[derive(Clone)] -enum Handle { - Master(PtyMaster), - Slave(PtySlave), -} +mod master; +mod pty; +mod resource; +mod scheme; +mod slave; -pub struct PtyScheme { - next_id: usize, - handles: BTreeMap, -} - -impl PtyScheme { - fn new() -> Self { - PtyScheme { - next_id: 0, - handles: BTreeMap::new(), - } - } - - fn get_handle(&self, id: usize) -> Option { - self.handles.get(&id).map(|handle| handle.clone()) - } -} - -impl SchemeMut for PtyScheme { - fn open(&mut self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { - let path = str::from_utf8(path).or(Err(Error::new(EINVAL)))?.trim_matches('/'); - - if path.is_empty() { - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, Handle::Master(PtyMaster::new(id, flags))); - - Ok(id) - } else { - let master_id = path.parse::().or(Err(Error::new(EINVAL)))?; - let handle = self.get_handle(master_id).ok_or(Error::new(ENOENT))?; - if let Handle::Master(master) = handle { - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, Handle::Slave(PtySlave::new(&master, flags))); - - Ok(id) - } else { - Err(Error::new(ENOENT)) - } - } - } - - fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result { - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let handle = self.get_handle(old_id).ok_or(Error::new(EBADF))?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, handle); - - Ok(id) - } - - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.get_handle(id).ok_or(Error::new(EBADF))?; - match handle { - Handle::Master(master) => master.read(buf), - Handle::Slave(slave) => slave.read(buf), - } - } - - fn write(&mut self, id: usize, buf: &[u8]) -> Result { - let handle = self.get_handle(id).ok_or(Error::new(EBADF))?; - match handle { - Handle::Master(master) => master.write(buf), - Handle::Slave(slave) => slave.write(buf), - } - } - - fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result { - match self.handles.get_mut(&id) { - Some(mut handle) => match *handle { - Handle::Master(ref mut master) => master.fcntl(cmd, arg), - Handle::Slave(ref mut slave) => slave.fcntl(cmd, arg), - }, - None => Err(Error::new(EBADF)) - } - } - - fn fevent(&mut self, id: usize, _flags: usize) -> Result { - let handle = self.get_handle(id).ok_or(Error::new(EBADF))?; - match handle { - Handle::Master(_master) => Ok(id), - Handle::Slave(_slave) => Ok(id), - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.get_handle(id).ok_or(Error::new(EBADF))?; - match handle { - Handle::Master(master) => master.path(buf), - Handle::Slave(slave) => slave.path(buf), - } - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { - let _handle = self.get_handle(id).ok_or(Error::new(EBADF))?; - - *stat = Stat { - st_mode: MODE_CHR | 0o666, - ..Default::default() - }; - - Ok(0) - } - - fn fsync(&mut self, id: usize) -> Result { - let handle = self.get_handle(id).ok_or(Error::new(EBADF))?; - match handle { - Handle::Master(_master) => Ok(0), - Handle::Slave(slave) => slave.sync(), - } - } - - fn close(&mut self, id: usize) -> Result { - drop(self.handles.remove(&id)); - - Ok(0) - } -} - -pub struct Pty { - id: usize, - miso: VecDeque>, - mosi: VecDeque, -} - -impl Pty { - pub fn new(id: usize) -> Self { - Pty { - id: id, - miso: VecDeque::new(), - mosi: VecDeque::new() - } - } - - pub fn path(&self, buf: &mut [u8]) -> Result { - let path_str = format!("pty:{}", self.id); - let path = path_str.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } -} - -/// Read side of a pipe -#[derive(Clone)] -pub struct PtyMaster { - pty: Rc>, - flags: usize, -} - -impl PtyMaster { - pub fn new(id: usize, flags: usize) -> Self { - PtyMaster { - pty: Rc::new(RefCell::new(Pty::new(id))), - flags: flags, - } - } - - fn path(&self, buf: &mut [u8]) -> Result { - self.pty.borrow_mut().path(buf) - } - - fn read(&self, buf: &mut [u8]) -> Result { - let mut pty = self.pty.borrow_mut(); - - if let Some(packet) = pty.miso.pop_front() { - let mut i = 0; - - while i < buf.len() && i < packet.len() { - buf[i] = packet[i]; - i += 1; - } - - Ok(i) - } else if self.flags & O_NONBLOCK == O_NONBLOCK || Rc::weak_count(&self.pty) == 0 { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&self, buf: &[u8]) -> Result { - let mut pty = self.pty.borrow_mut(); - - let mut i = 0; - while i < buf.len() { - pty.mosi.push_back(buf[i]); - i += 1; - } - - Ok(i) - } - - 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)) - } - } -} - -/// Read side of a pipe -#[derive(Clone)] -pub struct PtySlave { - pty: Weak>, - flags: usize, -} - -impl PtySlave { - pub fn new(master: &PtyMaster, flags: usize) -> Self { - PtySlave { - pty: Rc::downgrade(&master.pty), - flags: 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(); - - let mut i = 0; - - while i < buf.len() && ! pty.mosi.is_empty() { - buf[i] = pty.mosi.pop_front().unwrap(); - i += 1; - } - - if i > 0 || self.flags & O_NONBLOCK == O_NONBLOCK { - Ok(i) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } else { - Ok(0) - } - } - - fn write(&self, buf: &[u8]) -> Result { - if let Some(pty_lock) = self.pty.upgrade() { - let mut vec = Vec::new(); - vec.push(0); - vec.extend_from_slice(buf); - - let mut pty = pty_lock.borrow_mut(); - pty.miso.push_back(vec); - - Ok(buf.len()) - } else { - Err(Error::new(EPIPE)) - } - } - - fn sync(&self) -> Result { - if let Some(pty_lock) = self.pty.upgrade() { - let mut vec = Vec::new(); - vec.push(1); - - let mut pty = pty_lock.borrow_mut(); - pty.miso.push_back(vec); - - 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)) - } - } -} +use scheme::PtyScheme; fn main(){ // Daemonize @@ -356,61 +51,17 @@ fn main(){ } for (id, handle) in scheme.handles.iter() { - match *handle { - Handle::Master(ref master) => { - let pty = master.pty.borrow(); - if let Some(data) = pty.miso.front() { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: data.len() - }).expect("pty: failed to write event"); - } else if Rc::weak_count(&master.pty) == 0 { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: 0 - }).expect("pty: failed to write event"); - } - }, - Handle::Slave(ref slave) => { - if let Some(pty_lock) = slave.pty.upgrade() { - let pty = pty_lock.borrow(); - if ! pty.mosi.is_empty() { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: pty.mosi.len() - }).expect("pty: failed to write event"); - } - } else { - socket.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *id, - c: syscall::flag::EVENT_READ, - d: 0 - }).expect("pty: failed to write event"); - } - } + if let Some(count) = handle.fevent_count() { + socket.write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *id, + c: syscall::flag::EVENT_READ, + d: count + }).expect("pty: failed to write event"); } } } diff --git a/src/master.rs b/src/master.rs new file mode 100644 index 0000000000..74f18d8273 --- /dev/null +++ b/src/master.rs @@ -0,0 +1,103 @@ +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + +use syscall::error::{Error, Result, EINVAL, EWOULDBLOCK}; +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 PtyMaster { + pty: Rc>, + flags: usize, +} + +impl PtyMaster { + pub fn new(pty: Rc>, flags: usize) -> Self { + PtyMaster { + pty: pty, + flags: flags, + } + } +} + +impl Resource for PtyMaster { + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn pty(&self) -> Weak> { + Rc::downgrade(&self.pty) + } + + fn path(&self, buf: &mut [u8]) -> Result { + self.pty.borrow_mut().path(buf) + } + + fn read(&self, buf: &mut [u8]) -> Result { + let mut pty = self.pty.borrow_mut(); + + if let Some(packet) = pty.miso.pop_front() { + let mut i = 0; + + while i < buf.len() && i < packet.len() { + buf[i] = packet[i]; + i += 1; + } + + Ok(i) + } else if self.flags & O_NONBLOCK == O_NONBLOCK || Rc::weak_count(&self.pty) == 0 { + Ok(0) + } else { + Err(Error::new(EWOULDBLOCK)) + } + } + + fn write(&self, buf: &[u8]) -> Result { + let mut pty = self.pty.borrow_mut(); + + let mut i = 0; + while i < buf.len() { + pty.mosi.push_back(buf[i]); + i += 1; + } + + Ok(i) + } + + 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<()> { + Ok(()) + } + + fn fevent_count(&self) -> Option { + { + let pty = self.pty.borrow(); + if let Some(data) = pty.miso.front() { + return Some(data.len()); + } + } + + if Rc::weak_count(&self.pty) == 0 { + Some(0) + } else { + None + } + } +} diff --git a/src/pty.rs b/src/pty.rs new file mode 100644 index 0000000000..13a8ddbe56 --- /dev/null +++ b/src/pty.rs @@ -0,0 +1,66 @@ +use std::collections::VecDeque; + +use redox_termios::*; +use syscall::error::Result; + +pub struct Pty { + pub id: usize, + pub termios: Termios, + pub miso: VecDeque>, + pub mosi: VecDeque, +} + +impl Pty { + pub fn new(id: usize) -> Self { + let mut pty = Pty { + id: id, + termios: Termios::default(), + miso: VecDeque::new(), + mosi: VecDeque::new() + }; + + pty.termios.c_iflag = ICRNL | IXON; + pty.termios.c_oflag = OPOST | ONLCR; + pty.termios.c_cflag = B38400 | CS8 | CREAD | HUPCL; + pty.termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | IEXTEN; + + { + let mut cc = |i: usize, b: cc_t| { + pty.termios.c_cc[i] = b; + }; + + cc(VEOF, 0o004); // CTRL-D + cc(VEOL, 0o000); // NUL + cc(VEOL2, 0o000); // NUL + cc(VERASE, 0o177); // DEL + cc(VWERASE, 0o027); // CTRL-W + cc(VKILL, 0o025); // CTRL-U + cc(VREPRINT, 0o022);// CTRL-R + cc(VSWTC, 0o000); // NUL + cc(VINTR, 0o003); // CTRL-C + cc(VQUIT, 0o034); // CTRL-\ + cc(VSUSP, 0o032); // CTRL-Z + cc(VSTART, 0o021); // CTRL-Q + cc(VSTOP, 0o023); // CTRL-S + cc(VLNEXT, 0o026); // CTRL-V + cc(VDISCARD, 0o017);// CTRL-U + cc(VMIN, 1); + cc(VTIME, 0); + } + + pty + } + + pub fn path(&self, buf: &mut [u8]) -> Result { + let path_str = format!("pty:{}", self.id); + let path = path_str.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } +} diff --git a/src/resource.rs b/src/resource.rs new file mode 100644 index 0000000000..27f5bff606 --- /dev/null +++ b/src/resource.rs @@ -0,0 +1,18 @@ +use std::cell::RefCell; +use std::rc::Weak; + +use syscall::error::Result; + +use pty::Pty; + +pub trait Resource { + fn boxed_clone(&self) -> Box; + fn pty(&self) -> Weak>; + fn path(&self, buf: &mut [u8]) -> Result; + fn read(&self, buf: &mut [u8]) -> Result; + fn write(&self, buf: &[u8]) -> Result; + fn sync(&self) -> Result; + fn fcntl(&mut self, cmd: usize, arg: usize) -> Result; + fn fevent(&self) -> Result<()>; + fn fevent_count(&self) -> Option; +} diff --git a/src/scheme.rs b/src/scheme.rs new file mode 100644 index 0000000000..93783ef776 --- /dev/null +++ b/src/scheme.rs @@ -0,0 +1,121 @@ +use std::collections::BTreeMap; +use std::cell::RefCell; +use std::rc::Rc; +use std::str; + +use syscall::data::Stat; +use syscall::error::{Error, Result, EBADF, EINVAL, ENOENT}; +use syscall::flag::MODE_CHR; +use syscall::scheme::SchemeMut; + +use master::PtyMaster; +use pty::Pty; +use resource::Resource; +use slave::PtySlave; + +pub struct PtyScheme { + next_id: usize, + pub handles: BTreeMap>, +} + +impl PtyScheme { + pub fn new() -> Self { + PtyScheme { + next_id: 0, + handles: BTreeMap::new(), + } + } +} + +impl SchemeMut for PtyScheme { + fn open(&mut self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { + let path = str::from_utf8(path).or(Err(Error::new(EINVAL)))?.trim_matches('/'); + + if path.is_empty() { + let id = self.next_id; + self.next_id += 1; + + let pty = Rc::new(RefCell::new(Pty::new(id))); + self.handles.insert(id, Box::new(PtyMaster::new(pty, flags))); + + Ok(id) + } else { + let master_id = path.parse::().or(Err(Error::new(EINVAL)))?; + let pty = { + let handle = self.handles.get(&master_id).ok_or(Error::new(ENOENT))?; + handle.pty() + }; + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Box::new(PtySlave::new(pty, flags))); + + Ok(id) + } + } + + 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() + }; + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, handle); + + Ok(id) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.read(buf) + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.write(buf) + } + + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result { + let mut handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + handle.fcntl(cmd, arg) + } + + fn fevent(&mut self, id: usize, _flags: usize) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.fevent().and(Ok(id)) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.path(buf) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + *stat = Stat { + st_mode: MODE_CHR | 0o666, + ..Default::default() + }; + + Ok(0) + } + + fn fsync(&mut self, id: usize) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.sync() + } + + fn close(&mut self, id: usize) -> Result { + drop(self.handles.remove(&id)); + + Ok(0) + } +} diff --git a/src/slave.rs b/src/slave.rs new file mode 100644 index 0000000000..17e2b8a19b --- /dev/null +++ b/src/slave.rs @@ -0,0 +1,120 @@ +use std::cell::RefCell; +use std::rc::Weak; + +use syscall::error::{Error, Result, EINVAL, EPIPE, EWOULDBLOCK}; +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, +} + +impl PtySlave { + pub fn new(pty: Weak>, flags: usize) -> Self { + PtySlave { + pty: pty, + flags: flags, + } + } +} + +impl Resource for PtySlave { + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn pty(&self) -> Weak> { + self.pty.clone() + } + + 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(); + + let mut i = 0; + + while i < buf.len() && ! pty.mosi.is_empty() { + buf[i] = pty.mosi.pop_front().unwrap(); + i += 1; + } + + if i > 0 || self.flags & O_NONBLOCK == O_NONBLOCK { + Ok(i) + } else { + Err(Error::new(EWOULDBLOCK)) + } + } else { + Ok(0) + } + } + + fn write(&self, buf: &[u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let mut vec = Vec::new(); + vec.push(0); + vec.extend_from_slice(buf); + + let mut pty = pty_lock.borrow_mut(); + pty.miso.push_back(vec); + + Ok(buf.len()) + } else { + Err(Error::new(EPIPE)) + } + } + + fn sync(&self) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let mut vec = Vec::new(); + vec.push(1); + + let mut pty = pty_lock.borrow_mut(); + pty.miso.push_back(vec); + + 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(&self) -> Result<()> { + Ok(()) + } + + fn fevent_count(&self) -> Option { + if let Some(pty_lock) = self.pty.upgrade() { + let pty = pty_lock.borrow(); + if ! pty.mosi.is_empty() { + Some(pty.mosi.len()) + } else { + None + } + } else { + Some(0) + } + } +}